24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
说明:
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解法一
迭代版,设置一个指针 p 每次处理其后面的两个节点,若存在两个则进行交换,并更新 p 指针;若不足两个则结束处理。
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode p = dummyHead;
while (p.next != null && p.next.next != null) {
ListNode node1 = p.next;
ListNode node2 = p.next.next;
node1.next = node2.next;
node2.next = node1;
p.next = node2;
p = node1;
}
return dummyHead.next;
}
解法二
递归版,递归处理每一对节点,直到只有一个节点或者没有节点为止。
public ListNode swapPairs(ListNode head) {
if ((head == null)||(head.next == null))
return head;
ListNode n = head.next;
head.next = swapPairs(head.next.next); // 第一个节点连接后面那对节点
n.next = head; // 第二个节点指向第一个节点
return n; // 返回第二个节点
}
25. k个一组翻转链表
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解法一
与上一题不同的是,这题要求每k个节点进行反转。一个思路是用迭代法,每次进行反转之前,先判断是否有足够的k个节点,若不够则直接返回。否则说明有 k 个节点,只要依次反转后面的 k 个节点,更新指针,接着对下一组子链表的数量进行判断。
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode pre = dummyHead; // 定义:每组的前驱结点,pre.next指向的总是每组的开头结点
ListNode cur = pre.next; // 定义:初始时,每组的头结点,cur.next指向的总是下一个待反转结点
ListNode end = dummyHead; // 定义:找到每组的最后一个元素
// 开始反转,将每个待反转结点都插入头,作为头结点
while (true) {
end = pre; // 看余下的节点是否存在k个
int c = k;
while (end.next != null && c != 0) {
end = end.next;
c --;
}
// 不存在则结束循环
if ( c > 0 ) break;
// 存在则开始遍历k个节点的一组
int s = k;
while (--s > 0) { // 当头结点已经是初始状态下每组的最后一个结点时,结束循环,本组的链表倒转完成
ListNode node2 = cur.next;
cur.next = node2.next; // 这里维护了cur的定义
node2.next = pre.next; // 待插入结点指向目前每组的头结点
pre.next = node2; // 更新每组的头结点
}
pre = cur; // 注意pre的定义, cur结束时正好符合pre的定义
cur = pre.next;
}
return dummyHead.next;
}
解法二
这一题也可以用递归的解法,首先判断是否有足够的k个节点,若不够则直接返回。然后在反转时,head指针始终指向待反转链表的第一个节点,每次将其指向已经处理好的子问题的 pre 指针,更新 pre 和 head,继续反转完余下的节点。
public ListNode reverseKGroup(ListNode head, int k) {
// 判断是否有足够的k个节点,若不够则直接返回
ListNode node = head;
int count = 0;
while (count < k) {
if(node == null)return head;
node = node.next;
count++;
}
//pre 指针指向子问题的答案
ListNode pre = reverseKGroup(node, k);
// 反转k个节点
while (count > 0) {
ListNode next = head.next;
head.next = pre;
pre = head;
head = next;
count = count - 1;
}
return pre;
}
如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~