【问题标题】:Saving the linked list in java in leetcode add two numbersleetcode中java保存链表加两个数
【发布时间】:2020-08-08 02:04:30
【问题描述】:

我正在 Leetcode 上解决这个问题。但是,我在返回着墨列表时遇到了问题。

给定两个代表两个非负整数的非空链表。这些数字以相反的顺序存储,它们的每个节点都包含一个数字。将两个数字相加并作为链表返回。

您可以假设这两个数字不包含任何前导零,除了数字 0 本身。

例子:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

# Singly Linked List  #


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

问题

在我的代码的最后一部分,我意识到我无法将插入的数字保存在 head 中。我注意到 head.next = new ListNode(sum %10);` 正在覆盖我的节点。如何保存我的列表状态?

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        StringBuilder a = new StringBuilder();
        StringBuilder b = new StringBuilder();
        
        ListNode temp = l1;
        ListNode temp2 = l2;
        while(temp != null || temp2 != null) {
            a.append(temp.val);
            b.append(temp2.val);
            temp = temp.next;
            temp2 = temp2.next;
        }
       int sum =  Integer.parseInt(a.reverse().toString()) +                                                     Integer.parseInt(b.reverse().toString());
   
       ListNode head = new ListNode(0); 
       
        while(sum != 0) {
           head.next = new ListNode(sum % 10);
           head = head.next;
           sum /= 10;
        }
         
        return head;
    }

【问题讨论】:

    标签: java linked-list singly-linked-list


    【解决方案1】:

    问题出在head = head.next; 行。这是覆盖变量 head,这就是程序总是返回“最后一个”节点的原因。解决方案是返回一个不同的变量。 但是,还有另一个问题。 IE。你返回的列表总是有一个拖尾 0。对于您给出的示例输入,它返回 0->7->0->8 。这是因为您总是将列表初始化为 0。 这是一个可能的(不是那么优雅,但很快)的解决方案。

    编辑

    为了防止不同大小的列表出现 NullPointerException,字符串的生成放在一个方法中,每个列表调用一次。 增加空节点大小写管理

    编辑 2 新增功能重构和空节点案例管理

    public String nodeToString(ListNode l){
        StringBuilder a = new StringBuilder();
        ListNode temp = l;
        while(temp != null ) {
            a.append(temp.val);
            temp = temp.next;
            
        }
        return a.reverse().toString();
    }
    
    public Integer nodeToInt(ListNode l){
        String a=nodeToString(l);
        Integer ret=0;
        if(a.length()>0)
            ret=Integer.parseInt(a);
        return ret;
    }
    
    
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        
        
       Integer a=nodeToInt(l1);
       Integer b=nodeToInt(l2);
       int sum =  a+b;   
       ListNode head = new ListNode(sum % 10); 
       sum /= 10;
       
       ListNode retVal=head;
       
        while(sum != 0) {
           head.next = new ListNode(sum % 10);
           head = head.next;
           sum /= 10;
        }
         
        return retVal;
    }
    

    【讨论】:

    • 这将解决可变头问题的覆盖。但如果在 leetCode 上提交,它会抛出 NullPointerExpection。
    • 测试用例错误,如 l1 = [9,9,9] 和 l2 = [9]
    • 编辑了测试用例解决方案的答案。不清楚第一条评论的 prbl 是否与第二条相同
    • 第二条评论是第一条评论的测试用例。
    • 我重新设计了解决方案并在输入中添加了对空节点大小写的管理
    【解决方案2】:

    我们将使用sentinel node(就在head 或开始节点之前)来解决这个问题。然后,我们只需 return sentinel.next; 而不是 return head;

    这将通过:

    public final class Solution {
        public static final ListNode addTwoNumbers(
            ListNode l1, 
            ListNode l2
        ) {
            int left = 0;
            ListNode sentinel = new ListNode(0);
            ListNode tail = sentinel;
    
            while (!(l1 == null && l2 == null && left == 0)) {
                final int add1 = l1 != null ? l1.val : 0;
                final int add2 = l2 != null ? l2.val : 0;
                final int sum = add1 + add2 + left;
                left = sum / 10;
                final ListNode tempNode = new ListNode(sum % 10);
                tail.next = tempNode;
                tail = tempNode;
    
                if (l1 != null) {
                    l1 = l1.next;
                }
    
                if (l2 != null) {
                    l2 = l2.next;
                }
    
            }
    
            return sentinel.next;
        }
    }
    

    参考文献

    • 更多详细信息,请参阅Discussion Board,您可以在其中找到大量解释清楚且公认的解决方案,其中有多种languages,包括高效算法和渐近time/space 复杂性分析1,2.

    【讨论】:

      【解决方案3】:

      为什么不在迭代 l1 和 l2 时构建结果列表?我们不需要 StringBuilder、parseIntreverse()

      运行时间:1 毫秒,比 100.00% 的 Java 在线提交的两个数字相加更快。 内存使用量:39.6 MB,低于 75.33% 的 Java 在线提交的两个数字相加。

      这是我的解决方案

      class Solution {
      public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
          ListNode res = new ListNode(0);
          ListNode ret = res;
          int carry = 0;
          while (l1 != null || l2 != null) {
              int a = l1 == null ? 0 : l1.val;
              int b = l2 == null ? 0 : l2.val;
              l1 = l1 == null ? null : l1.next;
              l2 = l2 == null ? null : l2.next;
              res.next = new ListNode((a + b + carry) % 10);
              res = res.next;
              carry = ((a + b + carry) / 10);
          }
          if (carry != 0) res.next = new ListNode(carry);
          return ret.next;
      }
      

      }

      【讨论】:

      • 您能解释一下三元运算符吗?试图更好地理解你的逻辑
      • 我们知道每个节点都有一个值,l1 == null ? 0 : l1.val 如果 l1 节点为空,那么我将值视为 0 否则 l1.val 考虑案例[1],@987654328 @。第一次迭代后,l1 将为空,l2 现在指向第二个位置 (2)。现在我们将添加 0 + 2 并将其放入结果答案中。
      • l1 = l1 == null ? null : l1.next; l2 = l2 == null ? null : l2.next; 如果l1 已经为空,那么我们不会下一步增加/前进。想想我在上一条评论中提到的案例。在第 2 次迭代中,l1 已经为空,因此无需继续,但对于 l2,我们将继续 (l2.next)。
      猜你喜欢
      • 2021-08-20
      • 2020-04-16
      • 2018-10-25
      • 1970-01-01
      • 2023-01-19
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多