首页 > 其他分享 >LeetCode刷题day4——链表part2

LeetCode刷题day4——链表part2

时间:2024-06-22 00:01:03浏览次数:16  
标签:ListNode cur day4 nullptr next 链表 part2 curA 指针

24. 两两交换链表中的节点

用pre代表第1个节点,cur代表它后面的相邻节点,tmp存储cur->next。
但是问题找不到怎么返回新的节点。想着就循环一次,在第一次交换的时候就确认新的头结点。但还存在很多问题,具体如下:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (head == nullptr)  return head;
        // 奇数空一个,偶数交换
        ListNode* newhead = nullptr;

        ListNode* pre = head;
        ListNode* cur = head->next;
        while (cur != nullptr) {
            ListNode* tmp = cur->next; // 得知道交换完的下一个节点在哪
            cur->next = pre;
            pre->next = tmp;
            int loop = 1;
            if (loop--) {
                newhead = cur;
            }
            // 交换完一次++2
            pre = tmp;
            cur = pre->next;//如果pre已经是最后一个节点了则错误
            //而且这样交换的话,1没指向4
        }
        return newhead;
    }
};

卡哥:建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* cur = dummyhead;

        while(cur->next!=nullptr && cur->next->next!=nullptr){
            //交换
            ListNode* tmp1 = cur->next;
            ListNode* tmp2 = cur->next->next->next;
            
            cur->next = cur->next->next;//step1
            cur->next->next = tmp1;//step2
            tmp1->next = tmp2;//step3

            cur = cur->next->next;
        }

        ListNode* result = dummyhead->next;
        delete dummyhead;
        return result;
    }
};

19.删除链表的倒数第N个节点

1、遍历链表求取长度;2、size-n循环到要删除的节点的前一个节点;3、判断链表只有1个节点和其他情况。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* cur1 = dummyhead;
        int size = 0;
        while (cur1->next != nullptr) {
            cur1 = cur1->next;
            size++;
        }

        int loop = size - n;
        ListNode* cur2 = dummyhead;
        while (loop--) {
            cur2 = cur2->next;
        }
        // 此时cur为删除的前一个节点
        if (cur2->next->next != nullptr) {//如果只有一个节点的情况
            ListNode* tmp = cur2->next;
            cur2->next = cur2->next->next;
            delete tmp;
        }else{
            cur2->next = nullptr;
        }
        
        return dummyhead->next;
    }
};

卡哥:双指针应用——如果要删除倒数第n个节点,让fast移动n+1步,然后让fast和slow同时移动,直到fast指向链表末尾,这样才能slow指向删除节点的前一个节点了。
(n+1这个移动的步数 的思路得深度思考吸收)

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //fast指针走n+1步,
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* fastindex = dummyhead;
        ListNode* slowindex = dummyhead;
        while(n>=0 && fastindex!=nullptr){
            fastindex = fastindex->next; 
            n--;       
        }
        
        //然后同时移动slow fast,fast到null,slow才能指向删除的前一个节点
        while(fastindex!=nullptr){
            fastindex = fastindex->next;
            slowindex = slowindex->next;
        }
        
        slowindex->next = slowindex->next->next;
        ListNode* res = dummyhead->next;
        delete dummyhead;//一般自己new的要delete掉
        return res;
    }
};

面试题 02.07. 链表相交

错误点1:交点不是数值相等,而是指针相等。问题1:不知道怎么查询对比
卡哥:我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置。此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。否则循环退出返回空指针。在这里插入图片描述
根据卡哥思路自己写的代码:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int size_A = 0;
        int size_B = 0;
        //计算长度
        while(curA!=nullptr){
            size_A++;
            curA = curA->next;//忘记移动指针了
        }
        while(curB!=nullptr){
            size_B++;
            curB = curB->next;
        }
       //循环完cur在最后了需要重新赋值
       curA = headA;
       curB = headB;
        //循环到相同长度
        if(size_A>size_B && curA!=nullptr){
            int loop = size_A - size_B;
            while(loop--){
                curA = curA->next;
            }
        }else if(size_B>size_A && curB!=nullptr){
            int loop = size_B - size_A;
            while(loop--){
                curB = curB->next;
            }
        }
        
        //对比
        while(curA!=nullptr && curB!=nullptr){
            if(curA == curB){
                return curA;
            }else{
                curA = curA->next;
                curB = curB->next;
            }
        }
        //循环完没找到
        return nullptr;
        
    }
};

卡哥为了简化运算,可以直接对最大的一个操作:

 // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }

142.环形链表II(快慢指针)

快指针2个节点速度,慢指针1个节点速度,进入环1个节点的速度差,如果是别的可能就一直追不上了。
在这里插入图片描述
那么相遇时: slow指针走过的节点数为: x + y,为什么是x+y,而不是 x + 若干环的长度 + y 呢?图示,当慢指针(绿色)进入环的时候,快指针(红色)可以在环上的任意位置,最坏的情况就是快指针在慢指针前面一个结点,而按照相对运动来说,假设环有n个结点,则快指针相对慢指针运动n-1个单位时间即可追上。那么相等时间来说,慢指针最坏情况运动n-1个单位(不满一圈)就可以追上,所以是x+y。
在这里插入图片描述

fast指针走过的节点数:x + y + n (y + z),
因为fast走得快,在slow还没进来环之前它可能自己已经转了很多圈了。所以+n(y+z);n为fast指针在环内走了n圈才遇到slow指针,(y+z)为 一圈内节点的个数A。注意:n>=1。图示:最快情况下,慢指针刚进环下一个结点就被追上,此时fast走的路程为1*(y+z)+y。 我突然想到:可能有的人觉得最快应该是慢指针走到环入口的时候,快指针刚好已经提前走到环入口处了,那注意此时n不可能是0,如果是0,y=0,则x = x,相当于环入口那一刻相遇,但是x那一段线段路程,他两是不可能相遇的,所以n至少是1在里面转了一圈刚好到环入口才有可能相遇。
在这里插入图片描述
所以2*(x+y) = x+y+n(y+z)最终可以化解为x = (n - 1) (y + z) + z,当n=1时x=z,很重要这个信息,说明若有两个指针指向x和z的开始的话,他两同时移动,最后在环入口的时候相等;n>1时无非就是多转几圈,但最终还是环入口处相遇,所以其他转圈其实信息不重要,主要是看z=多少

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fastindex = head;
        ListNode* slowindex = head;
        while(fastindex!=NULL && fastindex->next!=NULL){//因为2步跳所以要判断2个
            fastindex = fastindex->next->next;
            slowindex = slowindex->next;
            if(fastindex == slowindex){
                //讲解中的x=z 两个指针出发在环入口相遇
                ListNode* index1 = fastindex;//存储相遇的点,此时快慢指针一样等于哪个都可以
                ListNode* index2 = head;//从头出发
                while(index1!=index2){
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return NULL;
    }
};

标签:ListNode,cur,day4,nullptr,next,链表,part2,curA,指针
From: https://blog.csdn.net/nosnef/article/details/139857973

相关文章

  • 【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
                   ......
  • 一千题,No.0089(链表元素分类)
    给定一个单链表,请编写程序将链表元素进行分类排列,使得所有负值元素都排在非负值元素的前面,而[0,K]区间内的元素都排在大于K的元素前面。但每一类内部元素的顺序是不能改变的。例如:给定链表为18→7→-4→0→5→-6→10→11→-2,K为10,则输出应该为-4→-6→-2→7→0→5→10......
  • c语音实现单链表初始化的四种方式
    typedefstructmyLink{ intdata; structmyLink*next;}myLink,*myLLink;1、对于上面的简单结构,用函数赋值需要传递引用,需要用到指针的指针。对指针使用不是很清楚的童鞋很是头痛。voidinitlink(myLink**head){ *head=(myLink*)malloc(sizeof(myLink)); if(......
  • 链表插入的小技巧
    一个带有优先级的链表:structlist{structlist*next;u32priority;} 如果要按照优先级插入某个新节点node,算法一般会写成:intlist_insert(list**head,list*new){if(head==null||*head==null||new==null)return1;list*prev......
  • 算法题---判断链表中是否有环,并找出环的入口
    方案一、利用Set集合不会重复的原理booleanjudgeCycle(Nodehead){Set<Node>visited=newHashSet<>();Nodenode=head;while(node!=null){if(visited.contains(node))returntrue;visi......
  • MySQL-Day4
    学习目标MySQL的内置函数concat拼接字符串函数把12,34,‘ab’,拼接成‘1234ab’selectconcat(12,34,'ab')length返回字符串字符的个数计算字符串长度‘abc’selectlength('abc')返回3一个utf-8,一个汉字表示3个长度selectlength(‘我和you’) 返回9内置函数可以......
  • JavaScript基础部分知识点总结(Part2)
    初识JavaScript1.JavaScript是什么JavaScript是世界上最流行的语言之一,是一种运行在客户端的脚本语言(Script是脚本的意思)脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行现在也可以基于Node.js技术进行服务器端编程2.JavaScript的作用表单动态校......
  • 软件测试理论基础Part2
    测试用例设计等价类划分法有效等价类满足需求的无效等价类不满足需求的等价类划分方法操作步骤明确需求确定有效和无效等价类编写测试用例边界值划分法边界范围上点处在边界上的点(正好等于)离点离上点最近的点内点范围内的点开区间,闭区......
  • 链表相对于数组的优势,以及栈和队列的基本操作
    链表(LinkedList)和数组(Array)是两种常见的数据结构,它们各自在不同的场景下有其优势和劣势。链表相对于数组的优势主要体现在以下几个方面:动态大小:链表在插入和删除元素时,不需要像数组那样预先分配固定大小的内存空间。链表中的节点可以动态地分配和释放,这使得链表在处理动......
  • 【Python】python实现双向链表
    一、定义与结构双向链表(DoublyLinkedList)是一种链式数据结构,每个节点(Node)包含三个部分:一个数据域(data),一个指向前驱节点的指针(prev),以及一个指向后继节点的指针(next)。双向链表的每个节点都链接到前一个节点和后一个节点,从而允许在两个方向上进行遍历。双向链表的结构+---......