Java内存超限问题,求讲解问题来源和解决方法的原理

滚动的黄埃 2024-03-04 16:29:25

今天在做算法题时遇到了内存超限,尽力优化也有一个超限。找了一些其他人的解法,对比发现关键只在两行的区别。

题目:

有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。
你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。
请问如何走才能拿到最多的金币。输入n,n*n的矩阵,金币数不超过1000(正整数)
输出最多拿多少金币
import java.util.Scanner;
public class njb {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] coins = new int[n][n];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                coins[i][j] = sc.nextInt();
            }
        }
        //这里设置M是为了防止内存超限,不是冗余
        int M = money(coins);
        System.out.println(M);
        //System.out.println(money(coins));
    }
    static int money(int[][] n){
        int [][] dp = new int[n.length][n.length];
        dp[0][0] = n[0][0];
        for (int i = 0; i < n.length; i++) {
            for (int j = 0; j < n.length; j++) {
                if (i == 0 && j>0) {
                    dp[0][j] = dp[0][j - 1] + n[0][j];
                } else if (j == 0 && i>0) {
                    dp[i][0] = dp[i - 1][0] + n[i][0];
                } else if(i > 0) {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + n[i][j];
                }
            }
        }
        return dp[n.length - 1][n.length - 1];
    }
}

关键在于M,不知道原理为何,求好心大佬解答 orz

...全文
1610 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
T0BSky 2024-05-22
  • 打赏
  • 举报
回复

在你描述的问题中,内存超限的问题主要出现在递归或者大量数据的情况下,Java会遇到内存限制。虽然你的代码实现中使用了动态规划来解决问题,但仍然可能由于N值较大而导致内存使用过多。

你的代码在解决最大金币问题时,使用了一个二维数组 dp 来存储每个位置上最大金币数的计算结果,这样的方式是常见的动态规划方法。关键是你提到的 M 变量,实际上在你的代码中 M 变量并不真正影响内存使用情况,可能是你在调试或测试过程中发现的一个误解。

内存超限问题的来源
内存消耗大:当N值很大时,创建一个N x N的二维数组会消耗大量内存。每个整型变量占用4字节,因此如果N过大,整个二维数组可能占用超过Java虚拟机的堆内存限制。

递归深度:如果使用递归算法且递归深度过深(例如没有优化的深度优先搜索),会导致栈内存溢出。

解决方法
优化动态规划表的大小:如果内存超限,首先要考虑的是减少内存的使用。例如在动态规划中,可以通过优化存储结构来减少内存使用。例如在这个问题中,只需要使用一维数组来保存当前行和上一行的最大金币数。

增大Java虚拟机堆内存:可以通过调整Java虚拟机参数来增加堆内存,例如 -Xmx 参数。

避免不必要的内存分配:检查代码中是否有不必要的内存分配,比如冗余的对象创建。

下面是使用一维数组优化动态规划存储的方法:

import java.util.Scanner;

public class njb {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] coins = new int[n][n];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                coins[i][j] = sc.nextInt();
            }
        }
        int M = money(coins);
        System.out.println(M);
    }

    static int money(int[][] n){
        int[] dp = new int[n.length];
        dp[0] = n[0][0];

        for (int i = 0; i < n.length; i++) {
            for (int j = 0; j < n.length; j++) {
                if (i == 0 && j > 0) {
                    dp[j] = dp[j - 1] + n[i][j];
                } else if (j == 0 && i > 0) {
                    dp[j] += n[i][j];
                } else if (i > 0 && j > 0) {
                    dp[j] = Math.max(dp[j], dp[j - 1]) + n[i][j];
                }
            }
        }

        return dp[n.length - 1];
    }
}

在这个优化版本中,我们使用一个一维数组 dp 来存储每行的最大金币数,这样可以将内存使用从 O(N^2) 降低到 O(N)。

内存优化的原理
状态压缩:通过使用一维数组代替二维数组,我们在每次迭代中仅保存当前行和上一行的状态,从而减少内存使用。
增大堆内存:可以通过运行时参数增加堆内存,避免因内存不足导致程序崩溃。
希望这些解释和优化方法能帮助你理解和解决Java中内存超限的问题。

h2plus0 2024-03-13
  • 打赏
  • 举报
回复

这个题目有问题吧, 因为题目限制只能向右边或下边走,所以, 移动的步数最大是 2n-1, 因此,
最多拿多少金币 = (2n-1) * 每个格子的金币数

ITjavaman 2024-03-11
  • 打赏
  • 举报
回复

方法一执行就会入栈,执行完毕就会出栈
相对比,多嵌了一层,开销相对就大了一点

51,411

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧