剑指offer链表题题解汇总

前述:

        我将会在此处持续更新我在刷题中遇到的链表类型题目,提交代码均为AC代码,如果有错,感谢您务必指正我。如果有更好的方法,欢迎指教!

面试问答汇总推荐链接:

C++设计模式(23种)汇总及代码实现_芒果甜汤圆的博客-优快云博客

计算机网络面经问答_芒果甜汤圆的博客-优快云博客

操作系统面试八股文合集_芒果甜汤圆的博客-优快云博客

史上最全C/C++面试八股文,一文带你彻底搞懂C/C++面试!_芒果甜汤圆的博客-优快云博客

题目:

JZ6 从尾到头打印链表(从尾到头打印链表_牛客题霸_牛客网 (nowcoder.com)

/*改题目没有给出具体的限制条件,直接顺序遍历链表,
将各个节点的值存储在容器中,然后使用翻转函数反转容器,最后顺序打印容器的值*/
#include <algorithm>
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int>ans;
        while(head){
            ans.push_back(head->val);
            head=head->next;
        }
        reverse(ans.begin(),ans.end());
        return ans;
    }
};

JZ24 反转链表(反转链表_牛客题霸_牛客网 (nowcoder.com)

/*
创建一个新结点,然后遍历链表,将各个节点使用头插法插在新节点中实现链表反转
*/
class Solution {
public:
    ListNode* ReverseList(ListNode* head) {
        if(!head) return nullptr;
        ListNode* h=new ListNode(0),*tmp1,*tmp2;
        while(head){
            tmp1=h->next;
            h->next=head;
            tmp2=head->next;
            head->next=tmp1;
            head=tmp2;
        }
        return h->next;
    }
};

JZ25 合并两个排序的链表(合并两个排序的链表_牛客题霸_牛客网 (nowcoder.com)

/*
先判断两个链表中是否存在空链表,如果有则直接返回另一个不为空的链表
同时遍历两个链表,比较两个节点的大小,将小的尾插到新节点(newHead)的尾节点(last)上,
较小的节点更新为它的后续节点,较大的不变继续等待下一次比较。直到有某个链表被遍历完
最后,因为题目没说两个链表等长,所以得判断哪个链表没被遍历完,将其剩余节点直接插入
*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1 || !pHead2) return !pHead1 ?pHead2 : pHead1;
        ListNode* newHead=new ListNode(0),*last=newHead;
        while(pHead1 && pHead2){
            if(pHead1->val > pHead2->val){
                last->next=pHead2;
                pHead2=pHead2->next;
            }else{
                last->next=pHead1;
                pHead1=pHead1->next;
            }
            last=last->next;
        }
        pHead1?last->next=pHead1:last->next=pHead2;
        return newHead->next;
    }
};

JZ52 两个链表的第一个公共结点(两个链表的第一个公共结点_牛客题霸_牛客网 (nowcoder.com)

/*
这里有一个小技巧就是,如图,红色箭头和绿色箭头走到交汇点的路程是相同的
同时出发,然后到达尾节点后从另一个链表表头再次出发。
具体实现就是利用两个标记,标记是否是第一次到达链表尾部
如果两个出发指针有一个到达了尾部,并且已经有一个已经重新开始过一次,那就说明没有共同节点

另外一种方法就是根据走过的路称来判断是否有公共点
*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
		if(!pHead1 || !pHead2) return nullptr;
        ListNode* start1=pHead1,*start2=pHead2;
		int flag1=0,flag2=0;
		while(1){
			if(!start1 && !flag1){
				start1=pHead2;
				flag1=1;
			}
			if(!start2 && !flag2){
				start2=pHead1;
				flag2=1;
			}
			if(start1==start2) return start1;
			if(!start1 || !start2 &&flag1) return nullptr;
			start1=start1->next;
			start2=start2->next;
		}
		return nullptr;
    }
};


class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode *p1=pHead1, *p2=pHead2;
        while (p1 != p2){
            p1 = p1 ? p1->next : pHead2;
            p2 = p2 ? p2->next : pHead1;
        }
        return p1;
    }
};

JZ23 链表中环的入口结点(链表中环的入口结点_牛客题霸_牛客网 (nowcoder.com)

/*
直接遍历链表,因为题目说val的值都大于0,我们将走过的节点的val标记为负数,
在遍历的过程中如果下一个节点的val是负数,那么就说明这个节点为入口,然后要再次遍历一下,把标记的负数还原,然后再返回
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        ListNode* h=pHead;
        while(pHead){
            if(pHead->next&&pHead->next->val<0){
                while(h!=pHead){
                    if(h->val<0) h->val=-h->val;
                    h=h->next;
                }
                pHead->val=-pHead->val;
                return pHead->next;
            } 
            pHead->val=-pHead->val;
            pHead=pHead->next;
        }
        return nullptr;
    }
};

JZ22 链表中倒数最后k个结点(链表中倒数最后k个结点_牛客题霸_牛客网 (nowcoder.com)

/*
先判断一下长度是不是小于k,小于k返回空
然后再判断一下剩余长度是不是等于总长,等于总长返回头节点
最后遍历一下,通过计数找到对应的节点
*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pHead, int k) {
        int len=0;
        ListNode* h=pHead;
        while(h){
            len++;
            h=h->next;
        }
        if(k>len) return nullptr;
        if(len==k) return pHead;
        h=pHead;
        int vis=len-k;
        len=0;
        while(h){
            len++;
            if(len==vis) return h->next;
            h=h->next;
        }
        return nullptr;
    }
};

JZ35 复杂链表的复制(复杂链表的复制_牛客题霸_牛客网 (nowcoder.com)

/*
先遍历一下,根据顺序创建新的节点,然后将新节点与被创建的旧节点建立对应关系
然后遍历旧节点,看是否有random节点,如果有则通过random节点找到对应的新节点,将其连接

*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead) {
        if(!pHead) return nullptr;
        unordered_map<RandomListNode*,RandomListNode*>mp;
        RandomListNode* ans=new RandomListNode(0),*pre=ans,*cur=pHead;
        while(cur){
            RandomListNode* tmp= new RandomListNode(cur->label);
            pre->next=tmp;
            mp[cur]=tmp;
            pre=pre->next;
            cur=cur->next;
        }
        for(auto& it:mp){
            if(it.first->random) it.second->random=mp[it.first->random];
        }
        return ans->next;
    }
};

JZ76 删除链表中重复的结点(删除链表中重复的结点_牛客题霸_牛客网 (nowcoder.com)

/*
这一题我是直接在原有结构上删除了节点,之前看错了题目以为是将有重复的节点删除只剩一个,题目意思是将有重复的节点全部删除。
我个人觉得题目的意思更偏向于直接把原有链表中的节点释放掉,而不是开新的节点

思路:
使用双指针,判断是否有重复的数字,如果有则将快指针在遍历的过程中的重复节点释放掉
然后使用临时变量记录慢指针的位置,慢指针指向快指针,再将临时变量记录的指针释放,直到慢指针指向空

另外一种则是使用队列

*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
        if(!pHead) return nullptr;
        ListNode* ans=new ListNode(0),*cur=pHead,*ne=pHead->next,*aa=ans;
        while(cur){
            int flag=0;
            while(ne && ne->val==cur->val){
                flag=1;
                ListNode* tmp=ne->next;
                delete ne;
                ne=tmp;
            }
            if(flag){
                ListNode* tmp=cur;
                cur=ne;
                delete tmp;
                ne=ne->next;
            }else{
                ListNode* tmp=cur->next;
                cur->next=nullptr;
                aa->next=cur;
                aa=aa->next;
                cur=tmp;
                ne=cur->next;
            }
        }
        return ans->next;
    }
};

JZ18 删除链表的节点(删除链表的节点_牛客题霸_牛客网 (nowcoder.com)

class Solution {
public:

    ListNode* deleteNode(ListNode* head, int val) {
        ListNode* h=new ListNode(0),*hh=h;
        h->next=head;
        while(h->next->val!=val) h=h->next;
        ListNode* tmp1=h->next,*tmp2=h->next->next;
        h->next=tmp2;
        delete tmp1;
        return hh->next;
    }
};

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

芒果甜汤圆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值