链表加法与节点交换:数据结构的基础技能

简介: 链表加法与节点交换:数据结构的基础技能


两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

我们依旧使用虚拟头节点来进行交换。

这张图很是清晰的标明了我们要做的交换步骤:

  1. 首先,创建一个虚拟头节点dummyHead,并将其next指针指向head。然后定义一个临时变量temp,将其初始化为dummyHead。
  2. 使用一个while循环遍历链表,直到遇到链表的末尾(即temp.next或temp.next.next为null)。
  3. 在循环中,首先将temp.next赋值给node1,将temp.next.next赋值给node2。然后将temp的next指针指向node2,将node1的next指针指向node2的next,最后将node2的next指针指向node1,然后把temp指向node1。
  4. 循环结束后,返回dummyHead.next,即交换后的链表的头节点。
public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode temp = dummyHead;
        while (temp.next != null && temp.next.next != null) {
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;
            temp.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            temp = node1;
        }
        return dummyHead.next;
    }

单链表加一

给定一个用单链表表示的整数,然后把这个整数加一。

public ListNode plusOne(ListNode head) {
        Stack<Integer> stack = new Stack<>();
        while (head != null) {
            stack.push(head.val);
            head = head.next;
        }
        int carry = 0;
        int adder = 1;
        ListNode dummy = new ListNode(0);
        while (!stack.isEmpty() || carry > 0) {
            int digit = stack.isEmpty() ? 0 : stack.pop();
            int sum = digit + carry + adder;
            carry = sum >= 10 ? 1 : 0;
            sum = sum >= 10 ? sum - 10 : sum;
            ListNode node = new ListNode(sum);
            node.next = dummy.next;
            dummy.next = node;
            adder = 0;
        }
        return dummy.next;
    }

我们的实现思路就是先把链表压入栈中,给最低位加一,用carry来记录是否有进位,然后用头插的方式把加一的链表连接起来。

  1. 首先创建一个空的栈(Stack)用于保存链表中的数字,并将链表中的每个节点的值依次入栈。
  2. 创建两个变量carry(进位)和adder(加法器),初始化carry为0, adder为1。
  3. 创建一个虚拟节点dummy,并将其值设置为0。用于存储相加后的链表。
  4. 进入while循环,直到栈为空且没有进位时结束循环。在每次循环中,我们从栈中弹出一个数字digit,并计算和sum = digit + carry + adder。
  5. 判断sum是否大于等于10,如果是,设置carry为1(表示进位),并将sum减去10。否则,carry为0。
  6. 创建一个新的节点node,值为sum,并将node插入到虚拟节点dummy之后。
  7. 继续进行下一次循环之前,将adder设为0,以确保下次循环只进行加法操作。
  8. 返回虚拟节点dummy的下一个节点,即加法操作完成后的链表头节点。

链表加法

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

我们用两种方式来实现:

使用栈实现

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<ListNode> stack1 = new Stack<>();
        Stack<ListNode> stack2 = new Stack<>();
        while (l1 != null) {
            stack1.push(l1);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2);
            l2 = l2.next;
        }
        ListNode dummy = new ListNode(-1);
        int carry = 0;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            ListNode a = new ListNode(0);
            ListNode b = new ListNode(0);
            if (!stack1.isEmpty()) {
                a.val = stack1.pop().val;
            }
            if (!stack2.isEmpty()) {
                b.val = stack2.pop().val;
            }
            int sum = carry + a.val + b.val;
            int ans = sum % 10;
            carry = sum / 10;
            ListNode cur = new ListNode(ans);
            cur.next = dummy.next;
            dummy.next = cur;
        }
        return dummy.next;
    }

以上代码实现了两个链表的加法操作。

  1. 首先创建两个栈stack1和stack2,分别用于存储链表l1和l2中的节点。
  2. 使用while循环,将链表l1和l2的节点依次入栈到stack1和stack2中。
  3. 创建一个虚拟节点dummy,并将其值设为-1,用于存储相加后的链表。
  4. 创建一个变量carry用于表示进位,初始值为0。
  5. 进入while循环,条件为stack1或stack2不为空,或者carry不为0。在每次循环中,我们从stack1和stack2中弹出当前节点的值。
  6. 创建两个新的节点a和b,并将它们的值设为stack1和stack2弹出的节点值。
  7. 计算和sum = carry + a.val + b.val,以及当前节点的值ans = sum % 10。
  8. 更新进位carry = sum / 10。
  9. 创建一个新的节点cur,将其值设为ans,并将cur插入到虚拟节点dummy之后。
  10. 继续进行下一次循环,直到stack1、stack2为空且carry为0。
  11. 返回虚拟节点dummy的下一个节点,即加法操作完成后的链表头节点。

使用链表反转实现

先将两个链表反转,然后计算结果之后,将结果进行反转。

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        l1 = reverse(l1);
        l2 = reverse(l2);
        ListNode head = new ListNode(-1);
        ListNode cur = head;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int val = carry;
            if (l1 != null) {
                val += l1.val;
                l1 = l1.next;
            }
            if (l2 != null) {
                val += l2.val;
                l2 = l2.next;
            }
            cur.next = new ListNode(val % 10);
            carry = val / 10;
            cur = cur.next;
        }
        if (carry > 0) {
            cur.next = new ListNode(carry);
        }
        return reverse(head.next);
    }
    public ListNode reverse(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

具体来说:

  1. 首先,将两个输入的链表l1和l2分别进行倒序处理,即反转链表。
  2. 创建一个新的虚拟头节点head,并创建一个指针cur来表示当前节点,初始时指向head
  3. 创建一个变量carry来表示进位,初始值为0。
  4. 进入循环,直到l1和l2都为空为止。在每次循环中,计算当前位的值val,并将carry加上对应位的值。
  5. 如果l1不为空,将l1的值加到val上,并将l1指向下一个节点。
  6. 如果l2不为空,将l2的值加到val上,并将l2指向下一个节点。
  7. 创建一个新的节点newNode,其值为val % 10,并将其插入到新链表中的下一个位置。
  8. 更新carryval / 10
  9. 更新当前节点cur为新插入的节点。
  10. 继续进行下一次循环。
  11. 如果最后还有进位,创建一个值为进位的新节点,并将其插入到新链表末尾。
  12. 将新链表进行反转,返回反转后的头节点。

这样,两个链表的倒序加法操作就完成了。

相关文章
|
23天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
50 4
|
24天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
25天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
1月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
26 7
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
25 3
|
1月前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
17 0
数据结构与算法学习五:双链表的增、删、改、查
|
23天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
40 0
|
1月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
18 0
LeetCode第二十四题(两两交换链表中的节点)
|
1月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
44 0
Leetcode第十九题(删除链表的倒数第N个节点)
|
1月前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
24 0