我正在解决编码挑战。在这个挑战中,我们将获得两个链接列表(2-> 4-> 3)和(5-> 6-> 4),我们必须返回它们相加的结果(7-> 0-> 8)。

在解决问题的同时,我在Google上找到了更好的版本:

ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
    ListNode preHead(0), *p = &preHead;
    int extra = 0;
    while (l1 || l2 || extra) {
        int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
        extra = sum / 10;
        p->next = new ListNode(sum % 10);
        p = p->next;
        l1 = l1 ? l1->next : l1;
        l2 = l2 ? l2->next : l2;
    }
    return preHead.next;
}

但是,我不理解ListNode preHead(0), *p = &preHead;步骤。 preHead的地址存储在指针变量p中。换句话说,p指向preHead。然后,为什么最后返回preHead.next?请注意,此代码会编译并返回预期的输出。

感谢您的帮助!

最佳答案

我喜欢称其为“虚拟节点模式”。在此处,用户将构造一个未使用的节点,以使插入和查找之类的事情容易实现。如您在函数中所见,p已经指向一个有效的节点开始,因此不需要检查p是否为NULL并将其设置为true,而是只需要使用p->next附加一个节点即可。这是p的起始值为NULL的备用代码:

ListNode* p = nullptr;
ListNode* tail;
while (l1 || l2 || extra) {
    //int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
    //extra = sum / 10;
    if (p != nullptr) {
        tail->next = new ListNode(sum % 10);
        tail = tail->next;
    } else {
        tail = p = new ListNode(sum % 10);
    }
    //l1 = l1 ? l1->next : l1;
    //l2 = l2 ? l2->next : l2;
}
return p;

我们将不得不在列表的末尾保留一个额外的指针,以便我们知道在每次迭代时要插入的位置。并且,在首次插入的情况下,我们必须确保p不是空指针。

返回preHead.next的原因是因为preHead.next是插入开始的位置(它是我们要返回的实际链接列表的开头)。

07-27 13:38