01 - 链表

18 阅读1分钟

1、反转链表

var reverseList = function (head) {
    let prev = null, cur = head;
    while (cur) {
        // 依次将head的第一个节点放到prev前面
        // [cur.next, prev, cur] = [prev, cur, cur.next];
        let temp = cur.next;
        cur.next = prev;
        prev = cur;
        cur = temp;
    }
    return prev
}

2、链表内指定区间反转

  • 给出的链表为 1→2→3→4→5→NULL, m=2,n=4,
  • 返回 1→4→3→2→5→NULL.
    const dummy_node = new ListNode(-1);
    dummy_node.next = head;

    let pre = dummy_node;
    for (let i = 0; i < m - 1; ++i) pre = pre.next;

    let cur = pre.next;
    for (let i = 0; i < n - m; ++i) {
        [pre.next, cur.next, pre.next.next] = [cur.next, cur.next.next, pre.next];
    }
    return dummy_node.next;
};

3、链表中的节点 每k个 一组翻转

  • 给定的链表是 1→2→3→4→5
  • 对于 k=2 , 你应该返回 2→1→4→3→5
  • 对于 k=3 , 你应该返回 3→2→1→4→5
function reverseKGroup(head, k) {
  let pre = null,
    cur = head,
    node = head;
  for (let i = 0; i < k; i++) {
    if (node === null) return head;
    node = node.next;
  }
  for (let j = 0; j < k; j++) {
    [cur.next, pre, cur] = [pre, cur, cur.next];
  }
  head.next = reverseKGroup(cur, k);
  return pre;
}

4、合并两个排序的链表

function Merge(pHead1, pHead2) {
    if (!pHead1) return pHead2;
    if (!pHead2) return pHead1;

    if (pHead1.val <= pHead2.val) {
        pHead1.next = Merge(pHead1.next, pHead2);
        return pHead1
    } else {
        pHead2.next = Merge(pHead2.next, pHead1);
        return pHead2
    }
}

5、判断链表中是否有环

// 使用快慢指针
var hasCycle = function (head) {
    let slow = head, fast = head;
    while (fast && fast.next) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) return true;
    }
    return false;
};

6、链表中环的入口结点

var detectCycle = function (head) {
    let cache = new Set();
    while (head) {
        if (cache.has(head)) {
            return head;
        } else {
            cache.add(head);
            head = head.next;
        }
    }
    return null;
};

7、返回链表中倒数最后 k个结点

  • 输入:{ 1, 2, 3, 4, 5 }, 2
  • 返回值:{ 4, 5 }
let FindKthToTail = function (pHead, k) {
    let fast = head, slow = head;
    for (let i = 0; i < k; i++) {
        if (!fast) return null;
        fast = fast.next;
    }
    while (fast) {
        fast = fast.next;
        slow = slow.next;
    }
    return slow;
}

8、删除链表的倒数第n个节点

let removeNthFromEnd = function (head, n) {
    let fast = head, slow = head;
    for (let i = 0; i < n; i++) {
        if (!fast.next) return head.next;
        fast = fast.next;
    }

    let pre;
    while (fast) {
        fast = fast.next;
        pre = slow;
        slow = slow.next;
    }
    pre.next = slow.next;
    return head;
}

9、两个链表的第一个公共结点

function FindFirstCommonNode(headA, headB) {
    let a = headA, b = headB;
    while (a != b) {
        a = a ? a.next : headB;
        b = b ? b.next : headA;
    }
    return a || b;
};

// 执行过程
--> [1, 2, 3, 6, 7][4, 5, 6, 7]
--> [2, 3, 6, 7][5, 6, 7]
--> [3, 6, 7][6, 7]
--> [6, 7][7]
--> [7] null
--> null[1, 2, 3, 6, 7]
--> [4, 5, 6, 7][2, 3, 6, 7]
--> [5, 6, 7][3, 6, 7]

10、判断一个链表是否为回文结构

function isPalindrome(head) {
    let positiveStr = ``, reverseStr = ``;

    while (head) {
        const val = head.val;
        positiveStr = positiveStr + val;
        reverseStr = val + reverseStr;
        head = head.next;
    }

    return positiveStr === reverseStr;
};

11、链表的奇偶重排

  • 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> NULL
  • 重排后为
  • 1 -> 3 -> 5 -> 2 -> 4 -> 6 -> NULL
function oddEvenList(head) {
    if (!head) return head;
    let odd = head, even = head.next, evenHead = even;
    while (even && even.next) {
        odd.next = odd.next.next;
        even.next = even.next.next;
        odd = odd.next;
        even = even.next;
    }
    odd.next = evenHead;
    return head
}

12、删除有序链表中重复的元素 - I

  • 给出的链表为1→1→2, 返回1→2.
  • 给出的链表为1→1→2→3→3, 返回1→2→3.
var deleteDuplicates = function (head) {
    var cur = head;
    while (cur && cur.next) {
        if (cur.val == cur.next.val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return head;
};

13、删除有序链表中重复的元素 - II

function deleteDuplicates(head) {
    if (!head || !head.next) return head;

    let res = new ListNode(-1);
    res.next = head;
    let prev = res, cur = res.next;

    while (cur && cur.next) {
        if (cur.val == cur.next.val) {
            while (cur.val == cur.next.val) {
                cur.next = cur.next.next;
                if (!cur.next) break;
            }
            prev.next = cur.next;
        } else {
            prev = cur;
        }
        cur = cur.next
    }
    return res.next;
}