使用ListNode实现两数相加时触发Java堆内存溢出问题排查
两数相加ListNode Demo内存溢出问题分析
核心问题定位
你遇到的java.lang.OutOfMemoryError: Java heap space确实和最后一个while循环直接相关,同时代码还存在其他隐性bug,逐一分析如下:
1. 结果链表构建逻辑错误(OOM直接诱因)
在addTwoNums方法的最后while循环中:
while(i < resultString.length()){ resultLN.val = Integer.parseInt(String.valueOf(resultString.charAt(i))); resultLN.next = resultLN; i ++; }
这段代码的问题是:每次循环都将resultLN的next指向自身,最终生成的是一个自循环的单节点链表,并没有创建多个节点来存储结果的每一位。
当后续调用toString方法时,toString里的循环会无限执行:
while(next != null){ value.append(next.val); next = next.next; }
因为next永远指向当前节点自身,循环永远不会终止,StringBuffer会不断扩容,最终耗尽Java堆内存,抛出内存溢出异常。
2. toString方法破坏原链表结构
ListNode的toString方法中,直接修改了当前节点的next成员变量:
while(next != null){ value.append(next.val); next = next.next; }
遍历完成后,当前节点的next会被置为null,原链表的结构被永久破坏,后续无法再正常遍历该链表。
3. 大数溢出风险
你通过将链表转成字符串再转成Integer的方式计算总和,当链表长度超过Integer的取值范围(最大为2^31-1,即10位数字)时,会直接抛出NumberFormatException,这不符合两数相加题目的设计初衷——题目本意就是处理无法用普通整数类型存储的大数。
修正方案
修正结果链表构建逻辑
正确的做法是逐个创建新节点,构建正常的单链表:
int i = 0; ListNode dummy = new ListNode(); ListNode current = dummy; while(i < resultString.length()){ int val = Integer.parseInt(String.valueOf(resultString.charAt(i))); current.next = new ListNode(val); current = current.next; i ++; } return dummy.next;
修正toString方法
避免修改原节点的next指针,使用临时变量遍历:
public String toString(){ StringBuffer value = new StringBuffer(); ListNode current = this; while(current != null){ value.append(current.val); current = current.next; } return value.toString(); }
推荐:逐位相加的正确实现(避免大数溢出)
按照题目要求,直接遍历两个链表的节点,逐位相加并处理进位,不需要转成整数:
public static ListNode addTwoNums(ListNode l1, ListNode l2){ ListNode dummy = new ListNode(); ListNode current = dummy; int carry = 0; while(l1 != null || l2 != null || carry > 0){ int sum = carry; if(l1 != null){ sum += l1.val; l1 = l1.next; } if(l2 != null){ sum += l2.val; l2 = l2.next; } carry = sum / 10; current.next = new ListNode(sum % 10); current = current.next; } return dummy.next; }
内容的提问来源于stack exchange,提问作者FelixSunYX
相关产品推荐
相关产品推荐

