C++牛客网编程(十五)

目录

链表中环的入口结点

链表中倒数最后第k个结点

复杂链表的复制


链表中环的入口结点

给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

数据范围: n≤10000n,1<=结点值<=10000

要求:空间复杂度 O(1),时间复杂度 O(n)

例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:

可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。

思路:a,b都从头结点开始,a每走一步,b走两步,当a和b相遇时,说明有环,否则若a或b为空则没有环。假设a和b在A点相遇(如下图),则a走了x+y步,b走了2(x+y)步,设环为r步,则2(x+y)=x+y+nr,可得x=nr-y,即b继续从A出发,a从头结点出发,会在B(环的入口)相遇。

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if(!pHead) return NULL;
        cout<<"phead"<<pHead->val<<endl;
        ListNode* a=pHead;
        ListNode* b=pHead;
        a=a->next;
        b=b->next->next;
        if(!a||!b) return NULL;
        while(b&&a&&a!=b){//a走一步,b走两步
            a=a->next;
            b=b->next->next;
        }
        if(!a||!b) return NULL;
        a=pHead;//a从链表头开始
        while(a!=b){//查找环的入口结点
            a=a->next;
            b=b->next;
        }
        return a;
    }
};

链表中倒数最后第k个结点

输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。

如果该链表长度小于k,请返回一个长度为 0 的链表。

数据范围:0≤n≤10^5,0≤ai≤10^9,0≤k≤10^9

要求:空间复杂度 O(n),时间复杂度 O(n)

进阶:空间复杂度 O(1),时间复杂度 O(n)

例如输入{1,2,3,4,5},2时,对应的链表结构如下图所示:

其中蓝色部分为该链表的最后2个结点,所以返回倒数第2个结点(也即结点值为4的结点)即可,系统会打印后面所有的节点来比较。

 思路:a为头结点,b从头结点向后移动到第k个结点,若b为空,则说明链表长小于k;从此时开始a和b同步向后移动相同结点,直到b为最后一个结点,此时a结点为倒数第k个结点。

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pHead, int k) {
        if(!pHead||k<1) return NULL;
        ListNode* a=pHead;
        ListNode* b=pHead;
        for(int i=1;i<k&&b;i++,b=b->next);
        if(!b) return NULL;
        while(b->next!=NULL){
            a=a->next;
            b=b->next;
        }
        return a;
    }
};

复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。

思路:有两种方法,第一个是在遍历建立next链表的同时,利用哈希表保存random指针值,第二个是直接在原链表上将每个结点拷贝一个放在原结点后面,最后将链表一分为二,如下图。

第一种方法:

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead) {
        if(!pHead) return NULL;
        unordered_map<RandomListNode*, RandomListNode*> mp;
        RandomListNode* p=new RandomListNode(0);
        RandomListNode* pre=p,*cur=pHead;
        while(cur){
            RandomListNode* clone=new RandomListNode(cur->label);
            pre->next=clone;
            mp[cur]=clone;
            pre=pre->next;
            cur=cur->next; 
        }
        for(auto&[key,value]:mp){
            value->random=key->random==NULL?NULL:mp[key->random];
        }
        delete p;
        return mp[pHead];
    }
};

第二种方法:

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead) {
        if(!pHead) return pHead;    // 为空则返回
        RandomListNode* cur = pHead;
        while(cur){
            RandomListNode* tmp = new RandomListNode(cur->label);    // 拷贝节点
            tmp->next = cur->next;
            cur->next = tmp;
            cur = tmp->next;
        }

        RandomListNode *old = pHead, *clone = pHead->next, *ret = pHead->next;
        while(old){
            clone->random = old->random == NULL ? NULL : old->random->next;    // 处理拷贝节点的随机指针
            if(old->next) old = old->next->next;    // 注意特判空指针
            if(clone->next) clone = clone->next->next;
        }

        old = pHead, clone = pHead->next;
        while(old){    // 拆分链表
            if(old->next) old->next = old->next->next;
            if(clone->next) clone->next = clone->next->next;
            old = old->next;
            clone = clone->next;
        }

        return ret;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值