LeetCode相关典型题解合集——链表

所有的题型目录在下面的链接
LeetCode相关典型题解合集(两百多道题)



一、160找出两个链表的交点

这道题目本质的思路是:走完自己的路,再走别人的路。两人走的总路程相同,遇到则返回,没遇到则返回null

当循环到第二轮的时候,两个链表若是没有相遇的节点,都会指向空节点,满足循环条件退出循环,因此不会形成死循环。

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //本质上是走过自己的路,再走过对方的路
        if(headA==NULL||headB==NULL){
            return NULL;
        }
        ListNode * t1=headA;
        ListNode *t2=headB;
        while(headA!=headB){
            if(headA==NULL){
                headA=t2;
            }
            else{
                headA=headA->next;
            }
            if(headB==NULL){
                headB=t1;
            }else{
                headB=headB->next;
            }
            
        }
        return  headA;
    }

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、206链表反转

有迭代和递归两种方法
迭代的思路就是三个节点,pre,cur和temp。pre和cur一次向后移,每次移动的时候都有cur.next->pre
递归就要熟悉递归的原理了

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //递归
        ListNode *pre=nullptr;
        ListNode *cur=head;
        while(cur!=nullptr){
            ListNode *temp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=temp;
        }
        return pre;
		
		/**********************/

		//递归
        if(head==nullptr||head->next==nullptr){
            return head;
        }
        ListNode *cur=reverseList(head->next);
        head->next->next=head;
        head->next=nullptr;
        return cur;
		
    }
};

三、21合并两个有序链表

分为递归和迭代两个方法。
递归自己好好体会
迭代是链表题中最经典的设置哨兵节点的方法,但是需要注意的是设置哨兵节点的时候尽量用哨兵节点->next=node这种表达,而不要用哨兵节点=node这种表达

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        /*********1、递归*************/
        //只要有一个链表为空就可以停止,做两次判断是因为不知道那一个链表先为空
        /*if(l1==nullptr){
            return l2;
        }
        if(l2==nullptr){
            return l1;
        }
        if(l1->val<l2->val){
            l1->next=mergeTwoLists(l1->next,l2);
            return l1;  //这个return l1或者l2是因为全部都递归遍历了,返回头结点。
        }else{
            l2->next=mergeTwoLists(l1,l2->next);
            return l2;
        }*/

        /*********2、迭代********************/
        //思路:一般链表的题目都要考虑一个前置pre节点作为记录节点,这样会解决很多问题(哨兵节点)
        ListNode *preHead=new ListNode(-1);
        ListNode *pre=preHead;
        while(l1&&l2){
            if(l1->val<=l2->val){
                pre->next=l1;
                l1=l1->next;
            }else{
                pre->next=l2;
                l2=l2->next;
            }
            pre=pre->next;
        }
        if(l1==nullptr){
            pre->next=l2;
        }
        if(l2==nullptr){
            pre->next=l1;
        }
        return preHead->next;
    }

四、19删除链表的倒数第n个节点

双指针的经典应用
另一个思路是用栈来写

 ListNode* removeNthFromEnd(ListNode* head, int n) {
        //双指针思想,以后这种倒数的长度类型的题目都可以用双指针
            ListNode *p=head;
            ListNode *q=head;
            int count=0;
            while(count<n){
                count++;
                q=q->next;
            }
            //当链表中q节点为空时,即删除的元素等于链表的长度
            //这时候其实是删除链表的第一个节点,所以返回head->next
            if(!q){
                return head->next;
            }
            while(q->next){
                p=p->next;
                q=q->next;
            }
            p->next=p->next->next;
            return head;
        }

五、24两两交换链表中的节点

一般涉及到交换和删除的节点操作,就要考虑设置一个前驱节点了

 ListNode* swapPairs(ListNode* head) {
 		//迭代
        ListNode *dummy=new ListNode(-1);
        dummy->next=head;
        ListNode *p=head;
        ListNode *q=new ListNode(-1);
        ListNode *temp=dummy;
        //之所以不用q来判断是因为若是q本身为空,则q->next会判错
        while(p&&p->next){
            q=p->next;
            p->next=p->next->next;
            q->next=p;
            temp->next=q;
            temp=p;
            p=p->next;
        }
        return dummy->next;

		/************************/
		//递归
		if(!head||!head->next){
            return head;
        }
        ListNode *temp=head->next;
        head->next=swapPairs(temp->next);
        temp->next=head;
        return temp;

六、445两数相加

这个题的思路使用栈做,链表用头插法。
需要注意的点在于一种情况:链表A为[5],链表B为[5]这种情况
因此,下面相加操作循环中的count!=0至关重要,表示还要进位

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> s1;
        stack<int> s2;
        ListNode *head=new ListNode(-1);
        while(l1){
            s1.push(l1->val);
            l1=l1->next;
        }
        while(l2){
            s2.push(l2->val);
            l2=l2->next;
        }
        ListNode *temp1=head;
        int count=0;
        int sum=0;
        int n1,n2;
        while(!s1.empty()||!s2.empty()||count!=0){
            //头插法
            if(s1.empty()){
                n1=0;
            }else{
                n1=s1.top();
                s1.pop();
            }
            if(s2.empty()){
                n2=0;
            }else{
                n2=s2.top();
                s2.pop();
            }
            sum=n1+n2+count;
            count=sum/10;
            ListNode *temp2=new ListNode(sum%10);
            temp2->next=temp1->next;
            temp1->next=temp2;
        }
        return head->next;
    }

七、234回文链表

递归有点难以理解,放个链接:递归解法

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        /************快慢指针+反转列表(效率爆炸)*******************/
        if(head==NULL||head->next==NULL){
            return true;
        }
        ListNode *slow=head;
        ListNode *fast=head;
        while(fast!=NULL&&fast->next!=NULL){
            slow=slow->next;
            fast=fast->next->next;
        }
        ListNode *cout=slow;
        ListNode *half=reverseNodeList(slow);
        bool flag=true;
        while(half!=NULL){
            if(head->val!=half->val){
                flag=false;
            }
            half=half->next;
            head=head->next;
        }
        return  flag;

        /**************递归*************************/
    }


    ListNode *reverseNodeList(ListNode *node){
        if(node->next==NULL){
            return node;
        }
        ListNode *dummyHead=NULL;
         ListNode *temp=NULL;
        while(node){
            temp=node->next;
            node->next=dummyHead;
            dummyHead=node;
            node=temp;
        }
        return dummyHead;
    }
};

八、725分隔链表

注意,用vector的时候不用考虑什么二维数组。
思路就是把链表断开

 vector<ListNode*> splitListToParts(ListNode* root, int k) {
        //1、计算链表的长度
        int count=0;
        ListNode *temp=root;
        while(temp){
            count++;
            temp=temp->next;
        }
        //2、计算分割的数量
        int length;
        length=(count/k)<1?1:count/k;
        int *arr=new int[k];
        for(int i=0;i<k;i++){
            arr[i]=length;
        }
        if(count>=k){
            int remainder=count%k;
            for(int i=0;i<remainder;i++){
                arr[i]=arr[i]+1; 
            }
        }
        //3、添加到vector
        vector<ListNode *> split;
        ListNode *dummy=NULL;
        for(int i=0;i<k;i++){
            split.push_back(root);
            for(int j=0;j<arr[i];j++){
                if(root!=NULL){
                    dummy=root;
                    root=root->next;
                }
            }
            if(dummy!=NULL){
                dummy->next=NULL;
            }
            
        }
        return split;
    }

九、328奇偶链表

写的时候有个细节需要注意,就是当所有奇数序列链表和偶数序列链表已经完成,需要合并的时候
这个时候如果直接合并,会出现问题。
因为如果是12345这种,135和24
4这个节点后面一定要让其指向空,不然会出问题

 ListNode* oddEvenList(ListNode* head) {
        //判断head为空,只有一个节点,两个节点的情况
        if(head==nullptr||head->next==nullptr){
            return head;
        }
        ListNode *oddNode=head;
        ListNode *evenNode=head->next;
        ListNode *temp=evenNode->next;
        ListNode *temp_evenNode=evenNode;
        int count=1;
        while(temp){
            if((count%2)!=0){
                //奇数序列
                oddNode->next=temp;
                oddNode=oddNode->next;
            }else{
                //偶数序列
                temp_evenNode->next=temp;
                temp_evenNode=temp_evenNode->next;
            }
            temp=temp->next;
            count++;
        }
        /*********最重要的两行************/
        temp_evenNode->next=nullptr;
        oddNode->next=evenNode;
        return head;
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值