Leetcode刷题_链表相关_c++版

(1)92反转链表–中等

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
在这里插入图片描述

/**
 * 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* reverseBetween(ListNode* head, int left, int right) {
    
    
            ListNode* new_head = NULL;
            ListNode* next = head;
            ListNode* pre_head = NULL;
            ListNode* latter_head = NULL;
            ListNode* reversed_first_node = NULL;
            int count = 1;
            while(head){
    
    
                if(left == right) return head;
                else if(count < left){
    
    
                    pre_head = next;
                    next = next->next;
                    count += 1;
                }
                else if (left <= count && count < right){
    
    
                    //逆置的长度如果只有1的话,就不需要逆置
                    //从最左边开始,没有pre_head
                    if(left == count) reversed_first_node = next;
                    if(left != 1) pre_head->next = next->next;
                    else head = next->next;
                    next->next = new_head;
                    new_head = next;
                    if(left == 1) next = head;
                    else next = pre_head->next;
                    count+=1;
                }
                else if (count == right){
    
    
                    latter_head = next->next;
                    if (left != 1) pre_head->next = latter_head;
                    next->next=new_head;
                    new_head = next;
                    next = latter_head;
                    //逆置完成,开始拼接
                    if (left != 1) pre_head->next = new_head;
                    reversed_first_node->next = latter_head;
                    break;
                }

            }return head;
    }
};

在这里插入图片描述

(2)160相交链表–简单

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
在这里插入图片描述


```cpp
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
#include<iostream>
class Solution {
    
    
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    
    
        
        if(headA == NULL or headB == NULL) return NULL;
        //_a标志从哪个点开始相同
        //_b标志正在检查哪个点
        ListNode* A_a = headA;
        ListNode* A_b = headA;
        ListNode* B_a = headB;
        ListNode* B_b = headB;
        //计算A和B的长度,方便末端对齐
        int count_A = 1;
        int count_B = 1;
        while(A_a){
    
    
            A_a = A_a->next;
            count_A++;
        }
        while(B_a){
    
    
            B_a = B_a->next;
            count_B++;
        }

        A_a = headA;
        B_a = headB;

        if(count_A > count_B){
    
    
            int len = count_A - count_B;
            while(len){
    
    
                A_a = A_a->next;
                len--;
            }A_b = A_a;
        }

        else if(count_A < count_B){
    
    
            int len = count_B - count_A;
            while(len){
    
    
                B_a = B_a->next;
                len--;
            }B_b = B_a;
        }
        cout<< A_a->val<< endl;
        cout<< B_a->val<< endl;
        //到此,两链表已经末端对齐

        while(A_b){
    
    
            //注意,是数值相等,不是指针相等
            if(A_b != B_b){
    
    
                A_a=A_b->next;
                A_b=A_b->next;
                B_a=B_b->next;
                B_b=B_b->next;
            }
            else{
    
    
                A_b = A_b->next;
                B_b = B_b->next;
            }

        }
        //cout<< A_a->val<< endl;
        return A_a;
    }
};

在这里插入图片描述

(3)142环形链表二–中等

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

在这里插入图片描述

法一:利用集合

#include<iostream>
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        std::set<ListNode*> nodeSet;
        if(head == NULL || head->next == NULL  ) return NULL;
        while(head){
    
    
            //cout<< head->val << endl;
            //在集合的非最后一个元素处找到该节点,则说明已经加过该节点,则该点为循环的起始点
            if(nodeSet.find(head) != nodeSet.end())
                return head;
            nodeSet.insert(head);
            head = head->next;
        }return NULL;
    }
};

在这里插入图片描述

法二:快慢指针赛跑

就像跑800,如果有环,快指针肯定能再一次相遇慢指针。
在这里插入图片描述

假设快指针每次走两步,慢指针每次走一步
在相同时间内,快指针走的距离是慢指针的两倍

a:起始点到环开始点的距离
b:环开始点到相遇点的距离
c:相遇点到环开始点的距离

快指针跑过的距离:a+b+c+b
慢指针跑过的距离:a+b

所以,a+b+c+b = 2*(a+b)
即:a = c
也就是说,从开始点和快慢指针相遇点一起开始向前走,一次走一格,如果到达了同一个点,即环开始的点

 #include<iostream>
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        if(head == NULL || head ->next == NULL) return NULL;
        //初始点位指向头结点
        ListNode* fastPoint = head->next->next;
        if(fastPoint == NULL) return NULL;
        cout<< fastPoint->val<< endl;
        //fastPoint = ;
        ListNode* slowPoint= head->next;
        //cout<<slowPoint->val<<endl;
        //slowPoint = head;
        while(fastPoint){
    
    
            //找到了相遇点就退出循环
            if(slowPoint == fastPoint) break;
            //快指针每次走两步,慢指针每次走一步
            slowPoint = slowPoint ->next;
            if(fastPoint -> next)
                fastPoint = fastPoint -> next -> next;
            else return NULL;
        }
        //cout<<slowPoint->val<<endl;
        if(fastPoint == NULL) return NULL;//如果走到了尽头,则说明没有环
        fastPoint = head;
        //*tmpPoint->next = &head;//tmpPoint回到头,开始以慢指针的速度开始走
        //两指针未相遇,就一直往前走
        while(fastPoint != slowPoint){
    
    
            fastPoint = fastPoint->next;
            slowPoint = slowPoint->next;
        }return slowPoint;
    }
};

(4)86分隔链表–中等

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。
在这里插入图片描述

class Solution {
    
    
public:

    ListNode* partition(ListNode* head, int x) {
    
    
        if(head == NULL || head->next ==NULL) return head;
        //设置两个临时头结点
        ListNode lessHead(0);
        ListNode moreHead(0);
        //对应指针分别指向这两个临时头结点
        ListNode* lessptr = &lessHead;
        ListNode* moreptr = &moreHead;
        while(head){
    
    
        	//比x大的插入到moreptr后
            if(head->val>= x){
    
    
                moreptr->next = head;
                moreptr = head;
            }
            //比x小的插入到lessptr后
            else{
    
    
                lessptr->next = head;
                lessptr = head;
            }
            head = head->next;
        }
        //两个链表相连
        lessptr->next = moreHead.next;
        moreptr->next = NULL;
        return lessHead.next;
    }
};

(5)138复制带随机指针的链表–中等

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

在这里插入图片描述

using namespace std;
class Solution {
    
    
public:
    Node* copyRandomList(Node* head) {
    
    
        vector<Node*> node_vec;//位置到节点的映射
        map<Node*, int> node_map;//地址到位置的映射
        Node* ptr = head;
        
        int i = 0;
        while(ptr){
    
    
            //生成新节点,放入列表
            node_vec.push_back(new Node(ptr->val));
            node_map[ptr] = i;
            i++;
            ptr = ptr->next;
        }
        node_vec.push_back(NULL);
        ptr= head;
        i=0;
        while(ptr){
    
    
            //新节点依次相连
            node_vec[i]->next = node_vec[i+1];
            if(ptr->random){
    
    
                //通过map,找出random到位置的映射
                int node = node_map[ptr->random];
                node_vec[i]->random = node_vec[node];
            }
            else node_vec[i]->random = NULL;
            ptr = ptr->next;
            i++;
        }
        return node_vec[0];
    }
};

在这里插入图片描述

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

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
在这里插入图片描述

/**
 * 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) {
    
    
        if(list1 == NULL ) return list2;
        if(list2 == NULL ) return list1;
        //设置一个头结点
        ListNode newnode(0);
        //newnode->val = 0;
        ListNode* newnodeHead = &newnode;
        //取两链表头结点,较小者插入新链表
        while(list1&&list2){
    
    
            if(list1->val <= list2->val){
    
    
                newnodeHead ->next = list1;
                list1 = list1->next;
            }
            else{
    
    
                newnodeHead ->next = list2;
                list2 = list2->next;
            }
            newnodeHead = newnodeHead->next;
            newnodeHead->next = NULL;
        }
        //将未空的链表直接接到新链表后
        if(list1 !=NULL){
    
    
            newnodeHead->next = list1;
        }
        else if(list2 !=NULL){
    
    
            newnodeHead->next = list2;
        }
        return newnode.next;
        }
    };

在这里插入图片描述

(7)23合并k个升序表–困难

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。
在这里插入图片描述
法一、二

/**
 * 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) {}
 * };
 */
 #include<iostream>
class Solution {
    
    
public:
    //自定义比较函数
    //如果不加static
    //非static成员函数在经过编译后编译器会他们添加一个this指针参数
    //变成bool cmp(Solution *this, const ListNode* a,const ListNode*b)
    //而标准库的sort()函数的第三个cmp函数指针参数中并没有这样this指针参数,因此会出现
    //cmp参数和sort()要求的参数不匹配,从而导致:
    //error: reference to non-static member function must be called

    //static静态类成员函数是不需要this指针的,因此改为静态成员函数即可通过
    static bool cmp(const ListNode* a,const ListNode*b){
    
    
        return a->val < b->val;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
    
    
        //if (lists.size() == 0) return NULL;
        //else if (lists[0] == NULL&& lists.size() == 1) return NULL;
        //假设链表长度为n,有k个链表
        //方式1:链表两两合并
        //时间复杂度为:(n+n)+(2n+n)+...+((k-1)*n+n) = O(k^2*N)=O(kn*k)
        //方式2:放入vector中,将vector排序,再将各个节点相连
        //时间复杂度为:O(kn*logkn)
        //当kn很大的时候,logkn小于k
        vector<ListNode*> points;
        ListNode* ptr = NULL;
        int listsLength = lists.size();
        for(int i = 0; i<listsLength; i++){
    
    
            ptr = lists[i];
            while(ptr){
    
    
                points.push_back(ptr);
                //cout<<ptr->val<<endl;
                ptr = ptr->next;
                
            }
        }
        if(points.size() == 0) return NULL;
        

        std::sort(points.begin(),points.end(),cmp);

        listsLength = points.size();
        for(int i = 0; i<listsLength-1; i++){
    
    
            points[i]->next = points[i+1];
        }points[listsLength-1]->next = NULL;
        return points[0];

        

        
    }
};

在这里插入图片描述

法三:分治

/**
 * 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) {}
 * };
 */
 #include<iostream>
class Solution {
    
    
public:
    //法三,时间复杂度为O(kn*logkn),链表较长时便可看出效率
    ListNode* mergeTowLists(ListNode* a,ListNode*b){
    
    
        if(a == NULL) return b;
        if(b == NULL) return a;
        ListNode newhead(0);
        ListNode* ptr = &newhead;
        while(a&&b){
    
    
            if(a->val<=b->val){
    
    
                ptr->next = a;
                a = a->next;
                ptr = ptr->next;
            }
            else{
    
    
                ptr->next = b;
                b= b->next;
                ptr = ptr->next;
            }
        }
        if(a) ptr->next = a;
        else ptr->next = b;
        return newhead.next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
    
    
        if (lists.size() == 0) return NULL;
        else if (lists.size() == 1) return lists[0];
        else if (lists.size() == 2) return mergeTowLists(lists[0],lists[1]);

        int mid = lists.size()/2;

        vector<ListNode*> sub_list1;
        vector<ListNode*> sub_list2;
        for(int i = 0; i< mid; i++) sub_list1.push_back(lists[i]);
        for(int i = mid; i< lists.size(); i++) sub_list2.push_back(lists[i]);

        ListNode* l1 = mergeKLists(sub_list1);
        ListNode* l2 = mergeKLists(sub_list2);

        return mergeTowLists(l1,l2);

        

        
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44343355/article/details/132864933