手把手刷数据结构-1.手把手刷链表算法

双指针秒杀7道链表题目

链接: labuladong的算法小抄.

合并两个有序链表

力扣: 合并两个有序链表.

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* dummy = new ListNode(-1), *p = dummy;
        ListNode* p1 = list1, *p2 = list2;

        while (p1 != nullptr && p2 != nullptr) {
            // 比较 p1 和 p2 两个指针
            // 将值较小的节点接到 p 指针
            if (p1->val > p2->val) {
                p->next = p2;
                p2 = p2->next;
            } else {
                p->next = p1;
                p1 = p1->next;
            }
            p = p->next;
        }
        if (p1 != nullptr) {
            p->next = p1;
        } 
        if (p2 != nullptr) {
            p->next = p2;
        }
        return dummy->next;
    }
};

合并 k 个有序链表

力扣: 合并k个有序链表.

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        // 优先队列,最小堆 无论入队顺序如何,都是当前最小的元素优先出队
        priority_queue<int> q;
        // 将所有值直接放入优先队列中
        for (ListNode* &t : lists) {
            while (t) {
                q.push(t->val);
                t = t->next;
            }
        }
        ListNode *last = NULL;
        while (!q.empty()) {
            ListNode *p = new ListNode(q.top());
            q.pop();
            p->next = last;
            last = p;
        }
        return last;
    }
};

单链表的倒数第 k 个节点

力扣: 单链表的倒数第 k 个节点.
在这里插入图片描述

class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) 
    {
        ListNode* fast = head;
        ListNode* later = head;

        while (fast && k > 0) {
            fast = fast->next;
            k--;
        }

        while (fast) {
            fast = fast->next;
            later = later->next;
        }
        return later;
    }
};

单链表的中点

链接: 单链表的中点.
在这里插入图片描述

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* fast = head, *slow = head;
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
};

判断链表是否包含环

链接: 判断链表是否包含环.
在这里插入图片描述

class Solution {
public:
    bool hasCycle(ListNode *head) {
           // 快慢指针初始化指向 head
        ListNode* fast = head, *slow = head;
         // 快指针走到末尾时停止
        while (fast != nullptr && fast->next != nullptr) {
              // 慢指针走一步,快指针走两步
            slow = slow->next;
            fast = fast->next->next;
            // 快慢指针相遇,说明含有环
            if (fast == slow) {
                return true;
            }
        }
        // 不包含环
        return false;
    }
};

链表中环的入口节点

进阶:链接: 链表中环的入口节点.
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head, *slow = head;
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
            if (fast == slow) break;
        }

        if (fast == nullptr ||fast->next == nullptr) {
            return nullptr;
        }

        slow = head;
        while (fast != slow) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};

两个链表是否相交

链接: 两个链表是否相交.
在这里插入图片描述

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // p1 指向 A 链表头结点,p2 指向 B 链表头结点
        ListNode* p1 = headA, *p2 = headB;
        while (p1 != p2) {
            // p1 走一步,如果走到 A 链表末尾,转到 B 链表
            if (p1 == nullptr) p1 = headB;
            else p1 = p1->next;
             // p2 走一步,如果走到 B 链表末尾,转到 A 链表
            if (p2 == nullptr) p2 = headA;
            else p2 = p2->next;
        }
        return p1;
    }
};

递归反转链表的一部分

反转链表

链接: 反转链表.

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 链表为空,返回,如果链表只有一个节点的时候反转也是它自己,返回。
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        ListNode* last = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return last;
    }
};

反转链表前N个节点

在这里插入图片描述
在这里插入图片描述

ListNode* successor = null; // 后驱节点

// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode *head, int n) {
    if (n == 1) {
        // 记录第 n + 1 个节点
        successor = head->next;
        return head;
    }
    // 以 head.next 为起点,需要反转前 n - 1 个节点
    ListNode* last = reverseN(head->next, n - 1);

    head->next->next = head;
    // 让反转之后的 head 节点和后面的节点连起来
    head->next = successor;
    return last;
}

反转链表II

链接: 反转链表II.

给一个索引区间 [m,n](索引从 1 开始),仅仅反转区间中的链表元素。
在这里插入图片描述
在这里插入图片描述
如果 m != 1 怎么办?如果我们把 head 的索引视为 1,那么我们是想从第 m 个元素开始反转对吧;如果把 head.next 的索引视为 1 呢?那么相对于 head.next,反转的区间应该是从第 m - 1 个元素开始的;那么对于 head.next.next 呢……

在这里插入图片描述

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        // base case
        if (left == 1) {
            return reverseN(head, right);
        }
        // 前进到反转的起点触发 base case
        head->next = reverseBetween(head->next, left - 1, right - 1);
        return head;
    }

    ListNode* successor = nullptr; // 后驱节点

    // 反转以 head 为起点的 n 个节点,返回新的头结点
    ListNode* reverseN(ListNode *head, int right) {
        if (right == 1) {
                // 记录第 n + 1 个节点
            successor = head->next;
            return head;
        }
        // 以 head.next 为起点,需要反转前 n - 1 个节点
        ListNode* last = reverseN(head->next, right - 1);

        head->next->next = head;
        // 让反转之后的 head 节点和后面的节点连起来
        head->next = successor;
        return last;
    }
};

如何K个一组反转链表

链接: 如何K个一组反转链表.

class Solution {
public:

    /** 反转区间 [a, b) 的元素,注意是左闭右开 */
    ListNode* reverse(ListNode* a, ListNode* b) {
        ListNode* pre = nullptr, *cur = a, *next = a;
        while (cur != b) {
            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        if (head == nullptr) return nullptr;
         // 区间 [a, b) 包含 k 个待反转元素
        ListNode* a, *b;
        a = b = head;
        for (int i = 0; i < k; i++) {
            // 不足 k 个,不需要反转,base case
            if (b == nullptr) return head;
            b = b->next;
        }
        // 反转前 k 个元素
        ListNode* newNode = reverse(a, b);
        a->next = reverseKGroup(b, k);
        return newNode;
    }
};

如何判断回文链表

链接: 如何判断回文链表.
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        ListNode* fast = head, *slow = head;
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }
        if (fast != nullptr) {
            slow = slow->next;
        }

        ListNode* left = head;
        ListNode* right = reverse(slow);

        while (right != nullptr) {
            if (left->val != right->val) {
                return false;
            }
            left = left->next;
            right = right->next;
        }
        return true;
    }

    ListNode* reverse(ListNode* head) {
        ListNode *pre = nullptr, *cur = head, *next = head;
        while (cur != nullptr) {
            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一记绝尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值