[路飞]_Leetcode链表算法合集(持续更新中...)

382 阅读4分钟

1. 删除链表的倒数第a个结点

给你一个链表,删除链表的倒数第 a个结点,并且返回链表的头结点。

image.png

1.1 双指针解题思路

如果要删除链表的倒数第a个结点,我们需要知道倒数第a个结点的前一个节点是哪个,然后将这个节点的next指向倒数第a个结点的next姐可以了。 想要要删除链表的倒数第a个结点,我们可以设置两个指针p、q,先让p走a个节点,再p、q同时走,这样等到p走到结尾的时候,q此时的位置就是倒数第a个节点的前一个节点了。

image.png

代码实现如下:

var removeNthFromEnd = function(head, n) {
    let newHead = new ListNode(0, head);
    let p = newHead;
    let q = newHead;
    while(n > 0) {
        p = p.next;
        n -= 1;
    }
    while(p.next !== null) {
        q = q.next;
        p = p.next;
    }
    q.next = q.next.next;
    return newHead.next;
};

2. 旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k个位置。

image.png

2.1 解题思路

首先,我们需要知道,当k等于链表长度(n)的时候,是不用移动的,所以k大于链表的长度的时候,需要求真正的移动次数,而它应该等于k%n。其次,就是链表移动k个位置,就是将指针从开始移动到n-k%n的位置,然后将当前的节点next指向null,再将最后的节点指向开始的节点就可以了。

image.png

代码实现如下:

var rotateRight = function(head, k) {
    if (!head) return null;
    let p = head;
    let i = 1;
    while(p.next) {
        i += 1;
        p = p.next;
    }
    p.next = head;
    k = k % i;
    k = i - k;

    while(k !== 0) {
        p = p.next;
        k -= 1;
    }
    const temp = p.next;
    p.next = null;
    return temp || p;
};

3. 删除排序链表中的重复元素

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。

返回同样按升序排列的结果链表。

3.1 解题思路

首先这个链表是已经排序好的,所以,重复的是连续的,所以在遍历的时候,将当前节点的值与它下一个节点比较,如果相同,则将它的next指向它的下一个节点的next,同时将当前节点变成下一个节点,不相同,就将当前节点变成下一个节点。

image.png

代码实现如下:

var deleteDuplicates = function(head) {
    let p = head;
    while(p) {
        if (p.next && p.val === p.next.val) {
            p.next = p.next.next;
        } else {
            p = p.next;
        }
    }
    return head;
};

4. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

点此解题LeetCode吧

4.1 解题思路

反转链表其实就是将当前节点的next指向它的上一个节点,所以我们可以定义两个变量,一个表示上一个节点,一个表示当前节点。

image.png

代码实现如下:

var reverseList = function(head) {
    if (!head || !head.next) return head;
    let p = head;
    let pre = null;
    while(p.next) {
        let temp = p;
        p = p.next;
        temp.next = pre;
        pre = temp;
    }
    p.next = pre;
    return p;
};

5. K个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
点此解题LeetCode吧

5.1 解题思路

我个人理解,这个题和反转链表可以使用差不多的思路去解决,只不过这个只是分组内的反转链表。需要明白的是,一组的链表反转完成后,它的头部节点会变成尾节点,尾节点变成头部节点,而它的尾节点的next应该指向的是下一个分组的头部节点。

代码实现如下

var reverseKGroup = function(head, k) {
    if (k === 0 || k === 1) {
        return head;
    }
    let i = 1;
    let newHead;
    let curGroupLastNode;
    let curGroupHead = head;
    let p = head;
    while(true) {
        if (i % k === 0) {
            if (curGroupLastNode) {
                curGroupLastNode.next = p;
            }
            curGroupLastNode = curGroupHead;
            curGroupHead = p.next;
            p.next = null;
            let q = reverseList(curGroupLastNode);
            
            if (!newHead) {
                newHead = q;
            }
            curGroupLastNode.next = curGroupHead;
            p = curGroupHead;
        } else {
            p = p.next; 
        }
        if (!p) {
            return newHead;
        }
        
        i += 1;
    }

    function reverseList(head) {
        if (!head || !head.next) return head;
        let p = head;
        let pre = null;
        while(p.next) {
            let temp = p;
            p = p.next;
            temp.next = pre;
            pre = temp;
        }
        p.next = pre;
        return p;
    };
    return head;
};

6. 返回倒数第 k 个节点

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

点此解题LeetCode吧

6.1 解题思路

这道题与删除链表倒数第a个结点的思路是一样的,只不过这个地方是返回next的val值。

代码实现如下:

var kthToLast = function(head, k) {
    let newHead = new ListNode(0, head);
    let p = newHead;
    let q = newHead;
    while(k > 0) {
        p = p.next;
        k -= 1;
    }
    while(p.next !== null) {
        q = q.next;
        p = p.next;
    }
    return q.next.val;
};