克服堆溢出问题

时间:2009-05-19 17:07:43

标签: java heap

我试图解决Project Euler的问题。我知道我的方法会在逻辑上起作用(它几乎立即返回小规模问题的答案)。然而,它可怕地扩展。我已经尝试更改.ini文件,但无济于事。

这是我的代码:

public class Number28 {

    static int SIZE = 101; //this should be an odd number, i accidentally posted 100
    /**
     * @param args
     */
    public static void main(String[] args) {
        double start = System.currentTimeMillis();
        long spiral[][]= spiral(SIZE);
        long sum = 0;
        for(int i = 0; i < SIZE; i++)
        {
            sum += spiral[i][i];
            sum += spiral[i][SIZE - 1 - i];
        }
        System.out.println(sum - 1);
        double time = System.currentTimeMillis() - start;
        System.out.println(time);

    }
    public static long[][] spiral(int size){
        long spiral[][]= new long[size][size];
        if(size == 1){
            spiral[0][0] = 1;
            return spiral;
        }
        else{
            long subspiral[][]= new long[size - 2][size - 2];
            subspiral = spiral(size - 2);
            for(int r = 0; r < size - 2; r++){
                for(int c = 0; c < size - 2; c++){
                    spiral[r + 1][c + 1] = subspiral[r][c];
                }
            }
            long counter = subspiral[0][size - 3];
            for(int r = 1; r < size ; r++){
                counter++;
                spiral[r][size - 1] = counter;
            }
            for(int c = size - 2; c >= 0; c--){
                counter++;
                spiral[size - 1][c] = counter;
            }
            for(int r = size - 2 ; r >= 0 ; r--){
                counter++;
                spiral[r][0] = counter;
            }
            for(int c = 1; c < size ; c++){
                counter++;
                spiral[0][c] = counter;
            }

            return spiral;
        }
    }
}

这是编辑过的代码,像宝石一样工作:

public class Number28 {
    static int SIZE = 1001;
    static long spiral[][]= new long[SIZE][SIZE];

    /**
     * @param args
     */
    public static void main(String[] args) {
        double start = System.currentTimeMillis();
        long spiral[][]= spiral(SIZE);
        long sum = 0;
        for(int i = 0; i < SIZE; i++)
        {
            sum += spiral[i][i];
            sum += spiral[i][SIZE - 1 - i];
        }
        System.out.println(sum - 1);
        double time = System.currentTimeMillis() - start;
        System.out.println(time);

    }
    public static long[][] spiral(int size){
        if(size == 1){
            spiral[SIZE / 2][SIZE / 2] = 1;
            return spiral;
        }
        else{
            long subspiral[][]= spiral(size - 2);
            int edge = (SIZE - size) / 2;
            long counter = subspiral[edge + 1][edge + size - 2];

              for(int r = 1; r < size ; r++){
                  counter++;
                  spiral[edge + r][edge + size - 1] = counter;
          }
          for(int c = size - 2; c >= 0; c--){
                  counter++;
                  spiral[edge + size - 1][edge + c] = counter;
          }
          for(int r = size - 2 ; r >= 0 ; r--){
                  counter++;
                  spiral[edge + r][edge] = counter;
          }
          for(int c = 1; c < size ; c++){
                  counter++;
                  spiral[edge][edge + c] = counter;
          }
            return spiral;
        }
    }
}

4 个答案:

答案 0 :(得分:5)

作为Project Euler建议的一般部分,如果您的解决方案无法扩展,那么几乎可以肯定有更好的方法来解决它。如果您在早期问题上使用了相同类型的解决方案,则可以通过前面问题的其他用户发布帖子,以获得以不同方式解决问题的想法。

答案 1 :(得分:4)

不熟悉欧拉问题,但恐怖似乎是你不断分配和重新分配什么是基本上一次性的中间螺旋,因为你递归地调用基本情况。

进行重组,以便预先分配完整的螺旋线。然后调用递归函数,通过引用将完整螺旋作为参数传递,同时传递“level”参数,该参数随每次递归调用而变化。例如,初始呼叫是100x100螺旋和100级; next(递归)调用具有相同的螺旋,通过引用和级别98.函数内的操作将全部在唯一分配的螺旋上完成。

简而言之:即使您以递归方式操作该数据结构,也要分配一次数据结构。

答案 2 :(得分:0)

我看到的第一个问题是在运行SIZE = 100的程序时出现NegativeArraySizeException。我想这与每个递归调用将大小减小2的方式有关。

我相信史蒂文的评论是正确的。您正在分配数组的大小,它们进行递归调用。这会导致(SIZE - 1)数组的数量分配,占用你所有的内存。删除那一行应该可以防止在必要时分配任何内存。

答案 3 :(得分:0)

这是一个不存储矩阵的简化解决方案:

public class P28 {

    private final static int N = 1001;

    public static void main(String[] args) {

        int limit = (N + 1) / 2;
        int sum = -3;
        int first = 4;
        int r = 20;
        for (int i = 1; i <= limit; i++) {
            sum += first;
            first += r;
            r += 32;
        }
        System.out.println(sum);
    }

}

<强>解释

1开始,你可以看到4个总和:

  • 1 + 3 + 13 + 31 + 57 + ...
  • 1 + 5 + 17 + 37 + 65 + ...
  • 1 + 7 + 21 + 43 + 73 + ...
  • 1 + 9 + 25 + 49 + 81 + ...

1添加了4次,这就是sum的默认值为-3的原因。

让我们收集这些款项:

  • 4 + 24 + 76 + 160 + 276 + ...... (这就是first4r20 = 24 - 4)
  • 的原因

您可以观察r每步增加32(24 - 4 = 32 + 76 - 24 = 32 + 32 + 160 - 76 = ...)和实际数字({ {1}})增加first