五道链表题


(“数据结构与算法之美” 专栏的课后思考题)
在做链表相关的算法题时, 要重点留意边界条件的处理

  • 如果链表为空时, 代码能否正常工作
  • 如果链表只包含一个结点时, 代码是否能正常工作
  • 如果链表只包含两个结点时, 代码是否能正常工作
  • 代码逻辑在处理头结点和尾结点的时候, 是否能正常工作
单链表反转
  1. 先处理头节点信息
  2. 循环到尾节点
  3. 处理尾节点信息
 public static Node reverseList(Node head) {
        if (head == null || head.next == null) return head;

        Node curr = head.next;
        Node prep = head;
        head.next = null;
        Node next = null;
        while (curr.next != null) {
            next = curr.next;
            curr.next = prep;
            prep = curr;
            curr = next;
        }
        curr.next = prep;
        return curr;
    }
链表中环的检测
  1. 慢指针一次走一步, 快指针一次走两步
  2. while 循环 快指针碰到null, 无环
  3. while 循环, 两指针相交, 有环.
public static boolean hasCycle(Node head) {
    if (head == null || head.next == null) return false;

    Node low = head;
    Node fast = head.next.next;
    while (fast != null && fast.next != null) {
        if (low == fast) return true;

        low = low.next;
        fast = fast.next.next;
    }
    return false;
}
合并两个有序链表

递归终止条件
l1 == null
l2 == null
递推公式
l1.next = merge(l1.next, l2)
l2.next = merge(l1, l2.next)

递归这么屌的吗?

public static Node mergeTwoLists(Node l1, Node l2) {
    if (l1 == null) return l2;
    if (l2 == null) return l1;

    if (l1.val <= l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}
删除链表倒数第n大元素
  1. 建立哨兵 fir, sec 均指向哨兵
  2. fir 走n+1步
  3. fir, sec一起平移,直到fir -> null
  4. sec.next 为要删除的节点,直接跳过即可
public static Node ahaha(Node head, int n) {
    Node help = new Node(0);
    help.next = head;
    Node fir = help;
    Node sec = help;
    //fir 前进n + 1步
    for (int i = 0; i <= n; i++) {
        fir = fir.next;
    }
    while (fir != null) {
        fir = fir.next;
        sec = sec.next;
    }
    sec.next = sec.next.next;
    return help.next;
}
寻找链表中间节点

不用哨兵项,fast跳到null, 为偶数个数结点。 fast 跳到倒数第一个结点, 为奇数个数结点。这两种情况下 low 前进一步。

public static Node middleNode(Node head) {
    Node low = head;
    Node fast = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        low = low.next;
    }
    return low;
}

快慢指针好像都涉及到
while(fast ! null && fast.next != null) 这个判断

猜你喜欢

转载自blog.csdn.net/weixin_41889284/article/details/88383755