c++数据结构与算法(1)——链表(双指针)

方法归纳,dummy节点、双指针

代表题型

21. 合并两个有序链表(简单)

23. 合并K个升序链表(困难)

141. 环形链表(简单)

142. 环形链表 II(中等)

876. 链表的中间结点(简单)

160. 相交链表(简单)

19. 删除链表的倒数第 N 个结点(中等)

---------------------------------------------------------------------------------------------------------------

合并两个有序链表

使用dummy节点,然后依次比较插入dummy节点后就行了,时间复杂度O(N),空间复杂度O(1)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode dummy;
        ListNode *p = &dummy;
        while (list1 && list2) {
            if (list1->val <= list2->val) {
                p->next = list1;
                list1 = list1->next;
            } else {
                p->next = list2;
                list2 = list2->next;
            }
            p = p->next;
        }
        p->next = list1 ? list1 : list2;
        return dummy.next;
    }
};

合并K个有序链表

思路一样,多一个取k个链表最小值

class Solution {
public:
    void insertlist(list<ListNode *> &list1, ListNode *node)
    {
        for (list<ListNode*>::iterator it = list1.begin(); it != list1.end(); it++) {
            if (node->val <= (*it)->val) {
                list1.insert(it, node);
                return;
            }
        }
        list1.push_back(node);
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int size = lists.size();
        list<ListNode *> list1;
        for (int i = 0; i < size; i++) {
            if (lists[i] != nullptr)
                insertlist(list1, lists[i]);
        }
        ListNode dummy;
        ListNode *p = &dummy;
        while (!list1.empty()) {
            ListNode *node = list1.front();
            list1.erase(list1.begin());
            p->next = node;
            p = p->next;
            if (node->next)
                insertlist(list1, node->next);
        }
        return dummy.next;
    }
};

删除倒数第N个元素

双指针方法,注意头节点也可能被删除,所以dummy节点也是必要的

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy;
        dummy.next = head;
        ListNode *s, *q;
        s = q = &dummy;
        for (int i = 0; i < n+1; i++) {
            if (q == nullptr)
                return head;
            q = q->next;
        }
        while (q) {
            s = s->next;
            q = q->next;
        }
        s->next = s->next->next;
        return dummy.next;
    }
};

环形链表

偷了两张图,说的很清楚

第一次相遇,快指针肯定比慢指针多走圆圈的一倍至n倍(理解下,周长固定,只要k足够大,肯定会相遇),对应2图方法就可以找到起始点了

 判断是否环形链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *s, *p;
        s = p = head;
        while (p && p->next) {
            p = p->next->next;
            s = s->next;
            if (p == s) //相遇成环
                return true;
        }
        //有终点,说明不成环
        return false;
    }
};

 判断是否成环,成环就返回入环起始点,否则返回null

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //先相遇
        ListNode *s, *f;
        s = f = head;
        while (f && f->next) {
            f = f->next->next;
            s = s->next;
            if (f == s) break; //成环
        }
        if (f == NULL || f->next == NULL) return NULL; //不成环
        //s重置,s,p速度一致再次相遇即入环点
        s = head;
        while (f != s) {
            f = f->next;
            s = s->next;
        }
        return s;
    }
};

链表的中间节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode *s, *f;
        s = f =head;
        while (f && f->next) {
            f = f->next->next;
            s = s->next;
        }
        return s;
    }
};

 相交链表

 通过图片可以得出一个结论相交部分必然在两个链表尾端,那么两个指针相同速度从A走完到B,从B走完到A,必然相交于相交部分的起始位置。假设相交部分长度为C,都走了A+B-C的距离。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *A = headA;
        ListNode *B = headB;
        while (A != B) {
            A = A == NULL ? headB : A->next;
            B = B == NULL ? headA : B->next;
        }
        return A;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值