前言
链表的题目,一般加一个哨兵节点都能够更好的进行处理
2. 两数相加
题目描述
解题思路
题目给的逆序恰好可以直接进行加法操作,个位开始,直接模拟即可
编写代码
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1 == null) return l2;
if(l2 == null) return l1;
int sum = 0;
ListNode newHead = new ListNode(0);
ListNode pre = newHead; // 尾插操作的尾指针
while(l1 != null || l2 != null || sum != 0) {
// 先加第一个节点
if(l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if(l2 != null) {
sum += l2.val;
l2 = l2.next;
}
pre.next = new ListNode(sum % 10);
sum /= 10;
pre = pre.next;
}
return newHead.next;
}
24. 两两交换链表中的节点
题目描述
解题思路
- 模拟,通过画图我们可以发现两两交换节点,会涉及到四个节点,把握好这四个节点的指向就没什么大问题了
- K个一组翻转链表(那么这个题目是不是可以理解为2个一组翻转链表呢)
编写代码
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode newHead = new ListNode(0);
newHead.next = head;
ListNode pre = newHead, cur = pre.next, next = cur.next, nnext = next.next;
while (cur != null && next != null) {
pre.next = next;
next.next = cur;
cur.next = nnext;
pre = cur;
cur = nnext;
if(cur != null) next = cur.next;
if(next != null) nnext = next.next;
}
return newHead.next;
}
143. 重排链表
题目描述
解题思路
模拟,画图
编写代码
public void reorderList(ListNode head) {
if(head == null || head.next == null || head.next.next == null) return;
// 1. 找中间节点
ListNode slow = head,fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 2. 拆分两个链表,并将后面的链表逆序
ListNode head2 = new ListNode(0);
ListNode cur = slow.next;
slow.next = null;
while (cur != null) {
ListNode next = cur.next;
cur.next = head2.next;
head2.next = cur;
cur = next;
}
// 3. 合并两个链表
ListNode cur1 = head, cur2 = head2.next;
ListNode ret = new ListNode(0);
ListNode prev = ret;
while (cur1 != null) {
prev.next = cur1;
cur1 = cur1.next;
prev = prev.next;
if(cur2 != null) {
prev.next = cur2;
cur2 = cur2.next;
prev = prev.next;
}
}
}
23. 合并 K 个升序链表
题目描述
解题思路
- 暴力,第一个跟第二个合并,然后合并后的结果跟第三个合并……
- 优先级队列:存储每个链表的头结点,每次出队列的就是所有链表中的最小元素了,队列为空就结束了
- 分治:归并排序
编写代码
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> queue = new PriorityQueue<>((o1,o2)->o1.val - o2.val);
for (int i = 0; i < lists.length; i++) {
if(lists[i] != null) {
queue.offer(lists[i]);
}
}
ListNode ret = new ListNode(0);
ListNode pre = ret;
while (!queue.isEmpty()) {
ListNode top = queue.poll();
pre.next = top;
pre = pre.next;
if(top.next != null) {
queue.offer(top.next);
}
}
return ret.next;
}
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists,0,lists.length-1);
}
private ListNode merge(ListNode[] lists, int left, int right) {
if(left > right) return null;
if(left == right) return lists[left];
// 拆分
int mid = (left + right) / 2;
ListNode l1 = merge(lists,left,mid);
ListNode l2 = merge(lists,mid+1,right);
// 合并
return mergeTwoList(l1, l2);
}
private ListNode mergeTwoList(ListNode l1, ListNode l2) {
ListNode ret = new ListNode(0);
ListNode prev = ret;
while (l1 != null && l2 != null) {
if(l1.val < l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
if(l1 == null) prev.next = l2;
if(l2 == null) prev.next = l1;
return ret.next;
}
25. K 个一组翻转链表
题目描述
解题思路
- 递归:看例子:先将1,2翻转,然后1.next = (3,4反转后的头结点)……
- 模拟:先计算有几组要反转,然后进行迭代反转即可
编写代码
public ListNode reverseKGroup(ListNode head, int k) {
ListNode tail = head;
for (int i = 0; i < k; i++) {
if(tail == null) return head;
tail = tail.next;
}
// 逆序[head,tail)
ListNode cur = head;
ListNode prev = null;
while (cur != tail) {
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
head.next = reverseKGroup(tail,k);
return prev;
}
链表题目总结
以下链表题目也可以刷