代码随想录60天刷题之链表(二) | Day4

目录

Day 4:

4.1 Leetcode24 两两交换链表中的节点

4.2 Leetcode19 删除链表的倒数第n个结点

4.3  Leetcode面试题02.07 链表相交

4.4 Leetcode142 环形链表II


Day 4:

4.1 Leetcode24 两两交换链表中的节点

力扣

注意:

  1. 虚拟头结点的建立,保证首元结点(或头结点)和其他结点操作一致
  2. 画图理逻辑,看看怎么交换,注意交换的前后顺序

代码:

    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyNode=new ListNode(-1);
        dummyNode->next=head;
        ListNode* pre=dummyNode;
        ListNode* cur=head;
        while(cur&&cur->next) 
        //必须保证cur和cur-next都不为空,才能进行交换,交换的就是这两个点。有一个为空,代表后面没节点或者只剩一个结点,退出循环
        {
          //交换节点
          ListNode* temp=cur->next->next;//cur->next不空时,cur->next->next才成立
          pre->next=cur->next;
          cur->next->next=cur;//cur后面一个结点的next指向,反向
          cur->next=temp;//cur指向cur后的第2个元素(即后面的后面)

          //移动pre和cur,使新位置和其实位置一致,pre指向操作点的前一个,cur指向操作点,这是原则
          pre=cur;
          cur=cur->next;
        }
        return dummyNode->next;
    }

4.2 Leetcode19 删除链表的倒数第n个结点

力扣

我的思路:看成总数第len-n+1个,需求链表总长度

代码随想录题解:fast从虚拟头结点先移动n步,然后fast和slow同时移动,当fast移动到末尾的NULL位置时,slow指向倒数第n个节点

//思路:倒数第n个,相当于正数第len-n+1个,用for循环到这即可。这里纯循环不做其他比较,用for更快不易出错

 //牛客剑指22是返回倒数第n个元素的值,不是删除,注意区别,那个更简单

 //先建个getLength函数,获取链表长度(也可合在一起)    

int getLength(ListNode* head)
    {
        ListNode* cur=head;
        int length=0;
        while(cur)
        {
            length++;
            cur=cur->next;
        }
        return length;
    }

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyNode=new ListNode(-1);
        dummyNode->next=head;
        ListNode* pre=dummyNode;
        ListNode* cur=head;
        int len=getLength(head);
        //题目给出了n<=len这个条件,所以不用判断n>len情况;如果是第一个元素,跳过for循环
        for(int i=1;i<=len-n;i++)//循环1次到第二个数,循环len-n次到第len-n+1个数,符合条件
        {
            pre=cur;
            cur=cur->next;
        }
        pre->next=cur->next;
        delete cur;
        return dummyNode->next;
    }

4.3  Leetcode面试题02.07 链表相交

力扣

注意:本题是求两个链表交点节点的指针。

但要特别注意,交点不是数值相等,而是指针相等,即结点ListNode* 相等

我的思路:做过,第一反应还是哈希表,此时空间复杂度为O(n)。又用了双指针连接法,提交时三目运算符前面的条件写错了,要注意。

方法3是代码随想录解法,没写。

    //方法1:以前做过,第一反应是哈希表:先遍历一个链表统计次数,再遍历另一个链表看出没出现过,出现即返回
    //注意结点相同,不是结点的值相等
    //空间复杂度O(n),时间复杂度O(n)
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_map<ListNode*,int> mp;//int表示前面节点出现的次数
        ListNode* cur=headA;
        while(cur)
        {
            mp[cur]++;
            cur=cur->next;
        }

        cur=headB;
        while(cur)
        {
            if(mp[cur]!=0)//说明出现过,或者mp.find[cur]!=mp.end(),find和.end()配合
            {
                return cur;
            }
            cur=cur->next;//此时不必再往哈希表里放了
        }
        return NULL;
    }

    
    //方法2:两个链表连接在一起,相当于各遍历 一个长度为(两个链表长度和+一个NULL位)的链表
    //空间复杂度O(1),时间复杂度O(n)
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //为了提高运算速度,可以把下面这两行加上,不加也能AC
        if(headA==NULL||headB==NULL)
        {
            return NULL;
        }
        ListNode* p=headA;
        ListNode* q=headB;
        while(p!=q)
        {
            p=p!=NULL?p->next:headB;//这一这里的条件一开始上下写错了,写成p->next=NULL了,这一导致找不到共同点时无限循环了
            q=q!=NULL?q->next:headA; //改成这个之后,找不到时,p和q同时到达NULL。第一次p和q不同时到达NULL
        }
        //遍历结束时,要么遍历完两个链表长度后,要么pq不为空,且p=q退出,找到交点;要么p和q同时相等,为NULL
        return p;//最后p=q
    }

    //方法3:快慢指针,统计长度,先让长度长的for循环走到相等处,再一起走,走到有一个为空或者相交处返回

4.4 Leetcode142 环形链表II

力扣

注意:以下是代码随想录题解,快慢指针总结的还是挺有用的。

  1. 可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

2、fast每次走两步,slow每次走一步,fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。

3、因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的不能跳过,所以fast一定可以和slow重合。

4、公式推导后:从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。

5、fast指针走过的节点数 = slow指针走过的节点数 * 2:

我的思路还是哈希表:空间复杂度O(n)

 //方法1:第一思路还是哈希表,遍历全装进哈希表,看有没有重复装的。空间复杂度为O(n)
    ListNode *detectCycle(ListNode *head) {
        unordered_map<ListNode*,int> mp;
        ListNode* cur=head;
        while(cur) //如果有环,一直循环;如果没环,到NULL退出循环
        {
            if(mp[cur]!=0)//已出现过
            {
                return cur; //返回环第一个结点

            }
            else//此处加不加else都行
            {
               mp[cur]++;
               cur=cur->next;
            }   
        }
        return NULL;
    }
    //方法2:代码随想录题解思路
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast&&fast->next)//当fast和fast->next不为空时循环,如果任一为空则没环
        {
            fast=fast->next->next;//移动两步,fast->next不空才有fast->next->next
            slow=slow->next;
            if(slow==fast)//找到相遇点
            {
                ListNode*index1=slow;//俩指针,一个指向头结点,一个指向相遇点
                ListNode*index2=head; //最好新定义两个,防止和while循环里的弄混,易出问题
                while(index1!=index2)//再次相遇即为环入口
                {
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;    
            }
        }
        return NULL; 
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值