【问题标题】:Unable to assign LinkedList head node in Java for future reference无法在 Java 中分配 LinkedList 头节点以供将来参考
【发布时间】:2016-09-30 10:49:51
【问题描述】:

我在尝试一个标准的面试题,就是以链表的形式添加两位数字,并返回添加的答案。问题来了:

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

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8

342 + 465 = 807 Make sure there are no trailing zeros in the output list So, 7 -> 0 -> 8 -> 0 is not a valid response even though

值仍然是 807。

现在,我正在编写的代码采用ListNode 数据类型形式的两个参数,这是LinkedLists 的起始节点。我不明白的是

  1. 如何维护列表的头节点以供以后参考?
  2. 按值调用和按引用调用在 Java 中如何工作?我已经在 C++ 中处理了指针和引用调用,但我现在一直在尝试 Java 中的东西,它非常不同。

    class ListNode {
        public int val;
        public ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    
    
    public class Solution {
    
        public ListNode reverse(ListNode head) {
            ListNode curr = head;
            ListNode next = null;
            ListNode prev = null;
            while (curr != null) {
                next = curr.next;
                curr.next = prev;
                prev = curr;
                curr = next;
            }
            head = prev;
            return head;
        }
    
    
        public ListNode addTwoNumbers(ListNode a, ListNode b) {
            ListNode node = null;
            ListNode head = null;
            boolean carry = false;
            while (a != null || b != null) {
                int f = 0, s = 0;
                if (carry) {
                    f++;
                }
                carry = false;
                if (a != null) {
                    f += a.val;
                    a = a.next;
                }
                if (b != null) {
                    s = b.val;
                    b = b.next;
                }
                if (f + s > 9) {
                    carry = true;
                }
                int curr = (f + s) % 10;
                node = new ListNode(curr);
                if (head == null) {
                    head = node;
                }
                node = node.next; //warning that 'value of node assigned is never used'
            }
            if (carry) {
                node = new ListNode(1);
            }
            printList(head);
            return node;
        }
    }
    

【问题讨论】:

  • “Java 中按值调用和按引用调用如何工作”Java 始终是call-by-value。但是在这种情况下,“值”的含义是令人困惑的:传递的变量的值,它可能是一个引用。因此,虽然引用的对象不是按值传递的,但引用该对象的变量是;这意味着您不能像在 C++ 中那样在单独的方法中交换值。
  • @AndyTurner 在 Java 中处理诸如此类的 LinkedList 问题的最佳方法是什么?痛苦地维护 head 和其他值,因为在 Java 中,如果我只是简单地做head = node,那么 head 的值会根据节点而变化,我最终无法检索 head 值。如何避免这种情况?

标签: java linked-list pass-by-reference


【解决方案1】:

node 扮演一个模棱两可的角色。

        node = new ListNode(curr);
        node = node.next; // assigns null

node 重命名为previous 并执行以下操作:

        int curr = (f + s) % 10;
        ListNode newNode = new ListNode(curr);
        if (head == null) { // Or `previous == null`
            head = newNode;
        } else {
            previous.next = newNode;
        }
        previous = newNode;

    ...
    return head;

处理head 的技术是使其成为容器类LinkedList 的私有字段。

在 java 中,参数传递是按值调用的:f(a) 永远不会更改变量 a:存储对象指针/值的槽。而是将对象指针/值压入堆栈。 (对象值可能会更改其字段。)

所以递归插入可能看起来像head = insert(head, ...)

在C上可以使用别名,不仅仅用于参数传递:

ListNode* head = NULL;
ListNode** node = &head;
shile (...) {
    ...
    *node = newNode;
    node = &(newNode->next);
}

【讨论】:

  • The technique to handle head is to make it a private field of a container class LinkedList 这正是我的想法。以前的方法似乎可以很好地解决这个问题,谢谢
  • 你的回答让我失望了。如果我在每个阶段打印head 和之前的值,我会得到相同的答案。看看这里的代码:ideone.com/N7dvLX
  • 请编辑您的答案。这将是` int curr = (f + s) % 10; ListNode newNode = new ListNode(curr); if (previous == null) { previous = newNode;头=新节点; } else { previous.next = newNode;上一个 = 上一个。下一个; }`
  • 我看到previous = previous.next 会将null 分配给previous 但在循环结束时将previous 设置为newNode。那么一切都应该工作。
  • 当previous 为null 并且你分配它newNode 时,你不需要做previous = previous.next。你已经在那里了。您只需要在以后的迭代中执行此操作。这是被接受的正确代码:ideone.com/f3yhBR
【解决方案2】:

为什么这么复杂?

public class Solution {

    public ListNode addTwoNumbers(ListNode a, ListNode b) {
        int firstNumber = nodeToNumber(a);
        int secondNumber = nodeToNumber(b);
        return numberToNode(firstNumber + secondNumber);
    }

    public int nodeToNumber(ListNode node) {
        if (node.next != null) return node.value + 10 * nodeToNumber(node.next);
        return node.value;
    }

    public ListNode numberToNode(int number) {
        ListNode result = new ListNode(number % 10);
        if (number > 10) result.next = numberToNode(number / 10);
        return result;
    }
}

【讨论】:

    猜你喜欢
    • 2021-01-06
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 2018-07-17
    • 2011-01-08
    • 1970-01-01
    • 2010-12-03
    相关资源
    最近更新 更多