重刷链表,做一个链表的总结,自用。
技巧篇
快慢指针的应用,环形链表和找中间节点,平移链表。
处理头节点的小技巧,设置一个dummy结点。
hashSet可以用来找相同结点,环形结点。
递归/迭代解题。
经典的链表题
链表排序,环形链表,合并链表,反转链表。
巧妙用到了多个题解结合,题解参考力扣官方题解:
143. 重排链表 找到中间节点+反转后半段+合并链表。
public void reorderList(ListNode head) {
ListNode middle = middle(head);
ListNode l2 = reverseList(middle.next);
ListNode l1 = head;
middle.next = null;
mergeList(l1, l2);
}
//反转链表, 递归
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
//快慢指针
public ListNode middle(ListNode head){
ListNode fast = head;
ListNode slow = head;
while(fast!= null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
public void mergeList(ListNode l1, ListNode l2){
while(l1 != null && l2 != null){
ListNode l1_tmp = l1.next;
ListNode l2_tmp = l2.next;
l1.next = l2;
l2.next = l1_tmp;
l1 = l1_tmp;
l2 = l2_tmp;
}
}
148. 排序链表自顶向下,先找到中点(快慢指针),然后递归排序左半边和右半边,最后合并结果。
public ListNode sortList(ListNode head) {
return sortList(head, null);
}
//递归,自顶向下合并
public ListNode sortList(ListNode head, ListNode tail){
if(head == tail){
return head;
}
//边界
if(head.next == tail){
head.next = null;
return head;
}
ListNode mid = middle(head, tail);
ListNode res = merge(sortList(head, mid), sortList(mid, tail));//范围
return res;
}
//合并有序链表
public ListNode merge(ListNode list1, ListNode list2){
ListNode dummy = new ListNode(-1);
ListNode pre = dummy;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
pre.next = list1;
list1 = list1.next;
}else{
pre.next = list2;
list2 = list2.next;
}
pre = pre.next;
}
pre.next = list1 == null? list2 : list1;
return dummy.next;
}
// 快慢指针
public ListNode middle(ListNode head, ListNode tail){
ListNode fast = head, slow = head;
while(fast != tail){
fast = fast.next;
slow = slow.next;
//空指针异常注意
if(fast != tail){
fast = fast.next;
}
}
return slow;
}
23. 合并K个升序链表类似上一题。
public ListNode reverseKGroup(ListNode head, int k) {
ListNode hair = new ListNode(0);
hair.next = head;
ListNode pre = hair;
while(head != null){
ListNode tail = pre;
for(int i = 0; i < k; i++){
tail = tail.next;
if(tail == null){
return hair.next;
}
}
ListNode nex = tail.next;
ListNode[] reverse = reverse(head, tail);
head = reverse[0];
tail = reverse[1];
//接回去
pre.next = head;
tail.next = nex;
pre = tail;
head = nex;
}
return hair.next;
}
public ListNode[] reverse(ListNode head, ListNode tail){
ListNode pre = tail.next;
ListNode curr = head;
while(pre != tail){
ListNode temp = curr.next;
curr.next = pre;
pre = curr;
curr = temp;
}
return new ListNode[]{tail, head};
}
//递归
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
//迭代
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}