链表相关题目的实现

1. 环形链表的插值

有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。
给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
测试样例:
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}

本质就是链表的插值

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class InsertValue {
public:
    ListNode* insert(vector<int> A, vector<int> nxt, int val) {
        // write code here
        auto res = createList(A, nxt);

        return insertList(res, val);
    }

private:
    // create the list
    ListNode * createList(vector<int> & A, vector<int> & nxt){
        ListNode myhead(0);
        ListNode * pre = &myhead;
        int count = 0;
        int id = 0;
        while (count < (int)nxt.size()){
            ListNode * newNode = new ListNode(A[id]);
            pre->next = newNode;
            pre = newNode;
            id = nxt[id];
            count++;
        }
        //pre->next = myhead.next;
        return myhead.next;
    }

    // insert node
    ListNode * insertList(ListNode * head, int val){
        ListNode myhead(0);
        myhead.next = head;
        ListNode * pre = &myhead;
        bool notfirst = false;
        //while (head != myhead.next || !notfirst){
        while (head){
            notfirst = true;
            if (val <= head->val){
                ListNode * newNode = new ListNode(val);
                pre->next = newNode;
                newNode->next = head;
                return myhead.next;
            }
            else{
                pre = pre->next;
                head = head->next;
            }
        }

        ListNode * newNode = new ListNode(val);
        pre->next = newNode;
        newNode->next = head;
        return myhead.next;
    }
};

2. 访问单个节点的删除

实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。
给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

把后面一个节点的值复制过来, 然后删除后面一个节点

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Remove {
public:
    bool removeNode(ListNode* pNode) {
        // write code here
        if (!pNode || !pNode->next)
            return false;

        pNode->val = pNode->next->val;
        pNode->next = pNode->next->next;
        return true;
    }
};

3. 链表的分化

对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。
给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
测试样例:
{1,4,2,5},3
{1,2,4,5}

分割成三段链表, 注意连接时候, 空链的判断

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Divide {
public:
    ListNode* listDivide(ListNode* head, int val) {
        // write code here
        if (!head) return nullptr;
        ListNode lower(0), higher(0), equal(0);
        ListNode * preLower = &lower, *preHigher = &higher, *preEqual = &equal;
        while (head){
            if (head->val < val){
                preLower->next = head;
                preLower = head;       
                head = head->next;
                preLower->next = nullptr;
            }
            else if (head->val > val){
                preHigher->next = head;
                preHigher = head;
                head = head->next;
                preHigher->next = nullptr;
            }
            else{
                preEqual->next = head;
                preEqual = head;
                head = head->next;
                preEqual->next = nullptr;
            }          
        }

        if (lower.next){
            preEqual->next = lower.next;
            preLower->next = higher.next;
        }
        else{
            preEqual->next = higher.next;
        }      

        return equal.next;
    }
};

4. 打印两个链表的公共值

现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。
给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
测试样例:
{1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]

类似归并排序的排序过程

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Common {
public:
    vector<int> findCommonParts(ListNode* headA, ListNode* headB) {
        // write code here
        vector<int> res;
        while (headA && headB){
            if (headA->val == headB->val){
                res.push_back(headA->val);
                headA = headA->next;
                headB = headB->next;
            }
            else if (headA->val < headB->val){
                headA = headA->next;
            }
            else{
                headB = headB->next;
            }
        }
        return res;
    }
};

5. 链表的k逆序

有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。
给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。

本质: 链表逆序

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class KInverse {
public:
    ListNode* inverse(ListNode* head, int k) {
        // write code here
        ListNode myhead(0);
        myhead.next = head;
        ListNode * pre = &myhead;

        int count = 1;
        while (head){
            head = head->next;
            count++;

            if (count >= k && head){
                ListNode * nextEnd = pre->next;
                ListNode * cur = pre->next;             
                ListNode * nextstart = head->next;
                ListNode * precur = head->next;

                while (cur != nextstart){
                    ListNode * next = cur->next;
                    cur->next = precur;
                    precur = cur;
                    cur = next;
                }
                pre->next = head;
                count = 1;

                pre = nextEnd;
                head = nextstart;
            }
        }

        return myhead.next;
    }
};

6. 链表指定值清除

现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
测试样例:
{1,2,3,4,3,2,1},2
{1,3,4,3,1}

本质: 链表删除节点

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class ClearValue {
public:
    ListNode* clear(ListNode* head, int val) {
        // write code here
        ListNode myhead(0);
        ListNode * pre = &myhead;
        myhead.next = head;
        while (head){
            if (head->val == val){
                pre->next = head->next;
                head = pre->next;
            }
            else{
                pre = pre->next;
                head = head->next;
            }
        }
        return myhead.next;
    }
};

7. 链表回文结构

请编写一个函数,检查链表是否为回文。
给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false

本质: 快慢指针分割链表, 链表逆序

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
    bool isPalindrome(ListNode* pHead) {
        // write code here
        ListNode * left = pHead, * right = nullptr;
        divide(left, right);
        right = reverse(right);

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

private:
    void divide(ListNode * & left, ListNode * & right){
        ListNode myhead(0);
        myhead.next = left;
        ListNode * l1 = &myhead, *l2 = &myhead;
        while (l2 && l2->next){
            l1 = l1->next;
            l2 = l2->next->next;
        }
        right = l1->next;
        l1->next = nullptr;
    }

    ListNode * reverse(ListNode * right){
        ListNode * pend = nullptr;
        while (right){
            ListNode * next = right->next;
            right->next = pend;
            pend = right;
            right = next;
        }

        return pend;
    }
};

8. 复杂链表复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。

leetcode 上的一道经典题目

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        RandomListNode * start = pHead;
        // clone
        while (pHead){
            RandomListNode * newNode = new RandomListNode(pHead->label);
            newNode->next = pHead->next;
            pHead->next = newNode;
            pHead = pHead->next->next;
        }
        // modify random pointer
        pHead = start;
        while (pHead){
            if (pHead->random)
                pHead->next->random = pHead->random->next;
            pHead = pHead->next->next;
        }
        // split
        RandomListNode myhead(0);
        RandomListNode * pre = &myhead;
        pHead = start;
        while (pHead){
            RandomListNode * tmp = pHead->next;
            pHead->next = tmp->next;
            pre->next = tmp;
            pre = tmp;
            pHead = pHead->next;
        }

        return myhead.next;
    }
};

9. 链表判环

如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。
给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。

本质: 快慢指针

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class ChkLoop {
public:
    int chkLoop(ListNode* head, int adjust) {
        // write code here
        ListNode myhead(0);
        myhead.next = head;
        ListNode *p1 = head, *p2 = head;
        while (p2 && p2->next){
            p1 = p1->next;
            p2 = p2->next->next;

            // has loop
            if (p1 == p2){
                p1 = myhead.next;
                while (p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                return p1->val;
            }
        }

        return -1;
    }
};

10. 无环单链表判相交

现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交。
给定两个链表的头结点headA和headB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。

本质:将两个链表统一成一样长度比较

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class CheckIntersect {
public:
    bool chkIntersect(ListNode* headA, ListNode* headB) {
        // write code here
        int lenA = 0;
        ListNode * pA = headA, *pB = headB;
        while (headA){
            lenA++;
            headA = headA->next;
        }

        int lenB = 0;
        while (headB){
            lenB++;
            headB = headB->next;
        }

        if (lenA > lenB){
            int gap = lenA - lenB;
            headA = pA;
            headB = pB;
            while (gap){
                headA = headA->next;
                gap--;
            }
        }
        else if (lenA < lenB){
            int gap = lenB - lenA;
            headB = pB;
            headA = pA;
            while (gap){
                headB = headB->next;
                gap--;
            }
        }

        while (headA && headB){
            if (headA == headB)
                return true;

            headA = headA->next;
            headB = headB->next;
        }
        return false;
    }
};

11. 有环单链表相交判断

如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。如果两个链表长度分别为N和M,请做到时间复杂度O(N+M),额外空间复杂度O(1)。
给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

区分两种情况:
这里写图片描述

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class ChkIntersection {
public:
    bool chkInter(ListNode* head1, ListNode* head2, int adjust0, int adjust1) {
        // write code here
        ListNode * p1 = chkLoop(head1);
        ListNode * p2 = chkLoop(head2);
        if (p1 == p2){
            //ListNode * res = chkIntersect(head1, head2, p1);
            return true;
        }
        else{
            ListNode * pcur = p1;
            bool flag = false;
            while (pcur != p1 || !flag){
                flag = true;
                pcur = pcur->next;
                if (pcur == p2)
                    return true;
            }
            return false;
        }
    }

private:
    ListNode * chkLoop(ListNode* head) {
        // write code here
        ListNode myhead(0);
        myhead.next = head;
        ListNode *p1 = head, *p2 = head;
        while (p2 && p2->next){
            p1 = p1->next;
            p2 = p2->next->next;

            // has loop
            if (p1 == p2){
                p1 = myhead.next;
                while (p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                return p1;
            }
        }

        return nullptr;
    }
};

12. 单链表相交判断

给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。
给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

本质: 上面几种讨论情形的综合情况

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class ChkIntersection {
public:
    bool chkInter(ListNode* head1, ListNode* head2, int adjust0, int adjust1) {
        // write code here
        ListNode * p1 = chkLoop(head1);
        ListNode * p2 = chkLoop(head2);

        if (p1 && !p2 || !p1 && p2)
            return false;
        else if (!p1 && !p2){
            ListNode * res = chkIntersect(head1, head2, nullptr);
            return res ? true : false;
        }
        else{
            if (p1 == p2){
                //ListNode * res = chkIntersect(head1, head2, p1);
                return true;
            }
            else{
                ListNode * pcur = p1;
                bool flag = false;
                while (pcur != p1 || !flag){
                    flag = true;
                    pcur = pcur->next;
                    if (pcur == p2)
                        return true;
                }
                return false;
            }
        }
    }

private:
    ListNode * chkLoop(ListNode* head) {
        // write code here
        ListNode myhead(0);
        myhead.next = head;
        ListNode *p1 = head, *p2 = head;
        while (p2 && p2->next){
            p1 = p1->next;
            p2 = p2->next->next;

            // has loop
            if (p1 == p2){
                p1 = myhead.next;
                while (p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                return p1;
            }
        }

        return nullptr;
    }

    ListNode * chkIntersect(ListNode* headA, ListNode* headB, ListNode * pend) {
        // write code here
        int lenA = 0;
        ListNode * pA = headA, *pB = headB;
        while (headA != pend){
            lenA++;
            headA = headA->next;
        }

        int lenB = 0;
        while (headB != pend){
            lenB++;
            headB = headB->next;
        }

        if (lenA > lenB){
            int gap = lenA - lenB;
            headA = pA;
            headB = pB;
            while (gap){
                headA = headA->next;
                gap--;
            }
        }
        else if (lenA < lenB){
            int gap = lenB - lenA;
            headB = pB;
            headA = pA;
            while (gap){
                headB = headB->next;
                gap--;
            }
        }

        while (headA != pend && headB != pend){
            if (headA == headB)
                return headA;

            headA = headA->next;
            headB = headB->next;
        }
        return nullptr;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值