【专题九】链表

115 阅读3分钟

前言

链表的题目,一般加一个哨兵节点都能够更好的进行处理

2. 两数相加

题目描述

image.png

解题思路

题目给的逆序恰好可以直接进行加法操作,个位开始,直接模拟即可

编写代码

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. 两两交换链表中的节点

题目描述

image.png

解题思路

  1. 模拟,通过画图我们可以发现两两交换节点,会涉及到四个节点,把握好这四个节点的指向就没什么大问题了
  2. K个一组翻转链表(那么这个题目是不是可以理解为2个一组翻转链表呢)

image.png

编写代码

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. 重排链表

题目描述

image.png

解题思路

模拟,画图

image.png

编写代码

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 个升序链表

题目描述

image.png

解题思路

  1. 暴力,第一个跟第二个合并,然后合并后的结果跟第三个合并……
  2. 优先级队列:存储每个链表的头结点,每次出队列的就是所有链表中的最小元素了,队列为空就结束了
  3. 分治:归并排序

image.png

编写代码

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 个一组翻转链表

题目描述

image.png

解题思路

  1. 递归:看例子:先将1,2翻转,然后1.next = (3,4反转后的头结点)……
  2. 模拟:先计算有几组要反转,然后进行迭代反转即可

编写代码

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;
}

链表题目总结

以下链表题目也可以刷

www.nowcoder.com/exam/oj

leetcode.cn/tag/linked-…