LeetCode 链表操作

lalala / 2023-05-03 / 原文

21. 合并两个有序链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode l1 = list1;
        ListNode l2 = list2;
        // 新链表头指针
        ListNode header = null;
        // 新链表后指针
        ListNode before = null;
        
        // 特别注意示例 [1,5] [1,2,4]
        while(l1 != null || l2 != null) {
            // 两者都没走到末尾,都不为空
            if (l1 != null && l2 != null) {
                // 两链表当前节点相同,加两个一样的到新链表,并同时向前走一步
                if (l1.val == l2.val) {
                    ListNode newNode1 = new ListNode(l1.val);
                    ListNode newNode2 = new ListNode(l2.val);
                    if (before != null) {
                        before.next = newNode1;
                    }
                    newNode1.next = newNode2;
                    before = newNode2;
                    // 两个相等,同时加入新链表,同时向前走一步
                    l1 = l1.next;
                    l2 = l2.next;
                    // 新链表头节点,只在为 null 的时候指定一次
                    if (header == null) {
                        header = newNode1;
                    }
                }
                // 两链表当前节点不同,加小的那个到新链表,并只将小的那个向前走一步
                else {
                    ListNode newNode = null;
                    if (l1.val < l2.val) {
                        newNode = new ListNode(l1.val);
                        // l1 当前比 l2 当前小,只把 l1 加入新链表,也只有 l1 向前走一步
                        l1 = l1.next;
                    }
                    else if (l2.val < l1.val) {
                        newNode = new ListNode(l2.val);
                        // l2 当前比 l1 当前小,只把 l2 加入新链表,也只有 l2 向前走一步
                        l2 = l2.next;
                    }
                    // 将新节点与之前的连上
                    if (before != null) {
                        before.next = newNode;
                    }
                    before = newNode;
                     // 新链表头节点,只在为 null 的时候指定一次
                    if (header == null) {
                        header = newNode;
                    }
                }
            }
            // 两链表有一者走到了末尾,将没走到末尾的那个当前节点加入新链表,并向前走一步
            else {
                ListNode newNode = null;
                if (l1 != null && l2 == null) {
                    // 只走还没走完的这个链表
                    newNode = new ListNode(l1.val);
                    l1 = l1.next;
                }
                else if (l2 != null && l1 == null) {
                    // 只走还没走完的这个链表
                    newNode = new ListNode(l2.val);
                    l2 = l2.next;
                }
                // 将新节点与之前的连上
                if (before != null) {
                    before.next = newNode;
                }
                before = newNode;
                 // 新链表头节点,只在为 null 的时候指定一次
                if (header == null) {
                    header = newNode;
                }
            }
            
        }
        return header;

    }
}

 

 

25. K 个一组翻转链表

写一个反转链表的公共方法 revers(ListNode listHead)

ki 表示走到了 k 组第几个;k 组第一个记为 kStart ; k 组最后一个记为 kEnd;前一个 k 组的尾巴记为 preKTail

每次走到 k 组最后一个的时候

  • ki 清零
  • kEnd 指向 null ,调用反转方法反转 kStart
  • 如果 preKTail 不为空,preKTail指向 kEnd,preKTail 变为 kStart (反转后 start 成了尾)

如果走到了末尾,而 ki >1 说明后面的不够 k 个一组,不用反转。因此 preKTail 直接指向 kStart

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode kStart = null;
        ListNode kCur = head;
        ListNode kEnd = null;

        ListNode preKtail = null;

        ListNode resHead = null;
        int ki = 1;
        while(kCur != null) {
            // 每次先缓存下一个节点,防止后面有变化
            ListNode nextNode = kCur.next;
            if (ki == 1) {
                // k 个一组的起始
                kStart = kCur;
            }
            if (ki == k) {
                kEnd = kCur;
                if (resHead == null) {
                    resHead = kEnd;
                }
                ki=0;
                // 切断与下一个 k 组的联系,使得反转链表的时候有尾指向null
                kEnd.next = null;
                // 上一个链表尾指向这个的最后一个(待翻转)
                if (preKtail != null) {
                    preKtail.next = kEnd;
                }
                // 反转链表
                reverseList(kStart);
                // 链表已经反转过,头成了尾巴
                preKtail = kStart;
            }
            ki++;
            kCur = nextNode;
            if (kCur == null && ki > 1) {
                // 没有任何完整的一组的情况
                if (resHead == null) {
                    resHead = kStart;
                }
                // 这些剩下的不用反转,因此上一个尾指向这一个头
                if (preKtail != null) {
                    preKtail.next = kStart;
                }
                break;
            }
        }
        return resHead;
    }

    private void reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null) {
            // 先缓存下一个节点。注意怎么反转链表,这个 Next 指针要每次循环新生成一个,不能定义一个全局的
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
    }
}