F
F
fh2018-11-11 15:25:22
Java
fh, 2018-11-11 15:25:22

Java Memory limit exceeded at programming olympiad?

While solving the Sequence Conversion problem , I ran into memory overrun on the 23rd test. I solved it in two ways:

Method 1 (Using a dictionary, passed 23 tests, 23 mb)
import java.util.*;
import java.io.*;
import java.util.stream.Collectors;
 
public class SequenceTransform {
    public static void main(String[] args) throws IOException {
        Scanner scan = new Scanner(new File("input.txt"));
        PrintWriter pw = new PrintWriter(new File("output.txt"));
        List<Integer> seq = new ArrayList<>(); // сама последовательность
        Map<Integer, Integer> eachCount = new HashMap<>(); // словарь ( число - кол-во)
        int n = scan.nextInt(); // кол-во чисел
        int num;
        for(int i = 0; i < n; i++) {
            num = scan.nextInt();
            seq.add(num);
            if (!eachCount.containsKey(num)){ // добавление в словарь числа, либо увеличение его кол-ва
                eachCount.put(num,1);
            } else {
                eachCount.put(num, eachCount.get(num) + 1);
            }
        }
        // сортировка словаря и получение самого частого числа
        List<Map.Entry<Integer, Integer>> sorted = new ArrayList<>(eachCount.entrySet()); 
 
        int max = sorted.stream().sorted((a,b) -> {
            if (a.getValue() != b.getValue())
                return b.getValue() - a.getValue();
            else
                return a.getKey() - b.getKey();
        }).limit(1).collect(Collectors.toList()).get(0).getKey();
        int max_count = eachCount.get(max);
        // удаление(как и сказано в условии) max'a и вставка в конец
        seq.removeIf(a -> a == max);
        for (int i = 0; i < max_count; i++)
            seq.add(max);
 
        seq.forEach(pw::println);
        pw.close();
    }
}

Method 2 (Using an array to count the number, passed 13 tests, 22 mb)
import java.util.*;
import java.io.*;
import java.util.stream.Collectors;

public class SequenceTransform {
    public static void main(String[] args) throws IOException {
        Scanner scan = new Scanner(new File("input.txt"));
        PrintWriter pw = new PrintWriter(new File("output.txt"));
        int N = scan.nextInt();
        List<Integer> seq = new ArrayList<>();
        final int million = 1000000;
        int[] count = new int[million * 2 + 1]; // два миллиона эл-ов, так как в условии сказано, что числа в диапазоне [-10^6; 10^6]
        for (int i = 0; i < N; i++){
            int num = scan.nextInt();
            seq.add(num);
            count[million + num]+=1;
        }
        int[] max = {0,0};
        for (int i = 0; i < count.length; i++){
            if (max[1] < count[i]){
                max[0] = i;
                max[1] = count[i];
            }
        }
        int max_num = max[0] - million;
        seq.removeIf(a -> a == max_num);
        for (int i = 0; i < max[1]; i++)
            seq.add(max_num);
        seq.forEach(pw::println);
        pw.close();
    }
}

Current attempt( 16 mb, 23 tests)
import java.util.*;
import java.io.*;

public class SequenceTransform {
    static int nexInt(Reader reader) throws  IOException{
        String c = Character.toString( (char) reader.read());
        String Int = "";
        while (!c.equals(" ") && !c.equals("\n") && !c.equals("\uFFFF")){
            if (!c.equals("\r")) Int = Int.concat(c);
            c = Character.toString( (char) reader.read());
        }
        return Integer.valueOf(Int);
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader (new FileReader("input.txt"));
        PrintWriter pw = new PrintWriter(new File("output.txt"));
        Map<Integer, Integer> eachCount = new HashMap<>();
        int n = nexInt(br);
        int[] seq = new int[n];
        for(int i = 0; i < n; i++) {
            int num = nexInt(br);
            seq[i] = (num);
            if (!eachCount.containsKey(num)){
                eachCount.put(num,1);
            } else {
                eachCount.put(num, eachCount.get(num) + 1);
            }
        }
        List<Map.Entry<Integer, Integer>> sorted = new ArrayList<>(eachCount.entrySet());
        Map.Entry<Integer, Integer> max = sorted.get(0);
        Map.Entry<Integer, Integer> el;
        for (int i = 0; i < sorted.size(); i++){
            el = sorted.get(i);
            if (max.getValue().compareTo(el.getValue()) <= 0){
                if (max.getValue().compareTo(el.getValue()) != 0)
                    max = el;
                else if (max.getKey().compareTo(el.getKey()) > 0)
                        max = el;
            }
        }
        int maxkey = max.getKey();
        int maxvalue = max.getValue();
        int[] ans = new int[n];
        int j = 0;
        for (int i = 0; i < n; i++){ // Новый массив, в котором самый частый элемент находится в конце.
            if (maxkey != seq[i]){
                ans[j] = seq[i];
                j++;
            }
        }
        for (int i = n - maxvalue; i < n ; i++){
            ans[i] = maxkey;
        }
        for (int x : ans)
            pw.print(x + " ");

        pw.close();
    }
}

There were questions:
How does the server count the memory?
How to reduce memory costs, because the first solution is not very expensive?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
StainlessDespair, 2018-11-11
@StainlessDespair

The first method has too many abstractions. When it comes to critical memory savings, you should immediately forget about the existence of the Stream API, try not to use autoboxing and try to use resources more efficiently. That's why they are Olympiad problems to write all sorts by hand instead of one-line streams, etc.
What can be done:
Regarding the calculation of memory by the server, most likely they simply start the virtual machine with the -Xmx16m parameter and react to OutOfMemoryError, but this is not accurate.
p.s. You can't compare Integer like this a.getValue() != b.getValue(). Integer is an object, equals should be used. And in the task it is said to separate the numbers in the output with spaces, and not with newlines, but this is so, by the way.

D
Dinar Zaripov, 2018-11-12
@Donquih0te

Remove Scanner and use BufferedReader

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question