目录
- 两两交换链表中的节点
- 单链表加一
- 链表加法
- 使用栈实现
- 使用链表反转实现
两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
我们依旧使用虚拟头节点来进行交换。
这张图很是清晰的标明了我们要做的交换步骤:
- 首先,创建一个虚拟头节点dummyHead,并将其next指针指向head。然后定义一个临时变量temp,将其初始化为dummyHead。
- 使用一个while循环遍历链表,直到遇到链表的末尾(即temp.next或temp.next.next为null)。
- 在循环中,首先将temp.next赋值给node1,将temp.next.next赋值给node2。然后将temp的next指针指向node2,将node1的next指针指向node2的next,最后将node2的next指针指向node1,然后把temp指向node1。
- 循环结束后,返回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来记录是否有进位,然后用头插的方式把加一的链表连接起来。
-
首先创建一个空的栈(Stack)用于保存链表中的数字,并将链表中的每个节点的值依次入栈。
-
创建两个变量carry(进位)和adder(加法器),初始化carry为0, adder为1。
-
创建一个虚拟节点dummy,并将其值设置为0。用于存储相加后的链表。
-
进入while循环,直到栈为空且没有进位时结束循环。在每次循环中,我们从栈中弹出一个数字digit,并计算和sum = digit + carry + adder。
-
判断sum是否大于等于10,如果是,设置carry为1(表示进位),并将sum减去10。否则,carry为0。
-
创建一个新的节点node,值为sum,并将node插入到虚拟节点dummy之后。
-
继续进行下一次循环之前,将adder设为0,以确保下次循环只进行加法操作。
-
返回虚拟节点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;}
以上代码实现了两个链表的加法操作。
-
首先创建两个栈stack1和stack2,分别用于存储链表l1和l2中的节点。
-
使用while循环,将链表l1和l2的节点依次入栈到stack1和stack2中。
-
创建一个虚拟节点dummy,并将其值设为-1,用于存储相加后的链表。
-
创建一个变量carry用于表示进位,初始值为0。
-
进入while循环,条件为stack1或stack2不为空,或者carry不为0。在每次循环中,我们从stack1和stack2中弹出当前节点的值。
-
创建两个新的节点a和b,并将它们的值设为stack1和stack2弹出的节点值。
-
计算和sum = carry + a.val + b.val,以及当前节点的值ans = sum % 10。
-
更新进位carry = sum / 10。
-
创建一个新的节点cur,将其值设为ans,并将cur插入到虚拟节点dummy之后。
-
继续进行下一次循环,直到stack1、stack2为空且carry为0。
-
返回虚拟节点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;}
具体来说:
-
首先,将两个输入的链表l1和l2分别进行倒序处理,即反转链表。
-
创建一个新的虚拟头节点
head
,并创建一个指针cur
来表示当前节点,初始时指向head
。 -
创建一个变量
carry
来表示进位,初始值为0。 -
进入循环,直到l1和l2都为空为止。在每次循环中,计算当前位的值
val
,并将carry
加上对应位的值。 -
如果l1不为空,将l1的值加到
val
上,并将l1指向下一个节点。 -
如果l2不为空,将l2的值加到
val
上,并将l2指向下一个节点。 -
创建一个新的节点
newNode
,其值为val % 10
,并将其插入到新链表中的下一个位置。 -
更新
carry
为val / 10
。 -
更新当前节点
cur
为新插入的节点。 -
继续进行下一次循环。
-
如果最后还有进位,创建一个值为进位的新节点,并将其插入到新链表末尾。
-
将新链表进行反转,返回反转后的头节点。
这样,两个链表的倒序加法操作就完成了。