代码随想录算法训练营Day4

文章讲述了使用链表数据结构解决编程问题的几种方法,包括交换链表中的节点对、删除链表的倒数第N个节点、找出两个链表的相交节点以及检测环形链表。关键在于理解和利用双指针技巧,以及在处理链表时注意节点的正确连接,尤其是最后一个节点。
摘要由CSDN通过智能技术生成

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

昨天把链表的性质以及几个常见问题弄清楚后做题明显顺了很多,每次做题前画一张图,谁指到谁弄清楚,再结合一些如双指针法这样的技巧,这些问题确实难度不大。这里特别提醒一下我在debug中出现的问题,报错提示是这样的heap-use-after-free,而通过return输出大法找到出错语句分析之后,我发现问题出在调整了链表关系后,我的最后一个结点并没有明确给出指向(其实是保留了原先指向),在学习了一些博客的说法后,最后一个结点必须明确给出指向什么地方,不然系统会认定这个单向的链表是不完整的,最后我补了一句尾结点指向NULL的语句后顺利AC。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* left=new ListNode(0);
         ListNode* right=new ListNode(0);
         ListNode* temp=new ListNode(0);
         ListNode* temp1=new ListNode(0);
         ListNode* temp2=new ListNode(0);
          ListNode* dummy=new ListNode(0);
          dummy->next=head;
         left->next=dummy;
         right=head;
         if (head==nullptr)
         {
             return head;
         }
         if (head->next==NULL)
         {
             return head;
         }
         temp2=head->next;
         while (right!=NULL)
         {
             if (right->next!=NULL)
             {
            temp=right->next;
            temp1=right->next->next;
            left->next=temp;
            temp->next=right;
            right->next=NULL;
            left=right;
            right=temp1;
             }
             else
             {
                 left->next=right;
                 return temp2;
             }
         }
         return temp2;
    }
};

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

这道题目也比较简单,用双指针法控制前后指针中间一共是N+1个结点,那么当右侧指针搜索至最后一个时,左侧指针的位置刚好就是倒数第N+1个结点,那么将倒数第N+1个结点的next指到下下个结点处即可,下面是代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *right=new ListNode(0);
       ListNode *left=new ListNode(0);
       int i;
       if (head->next==NULL)
       {
           return nullptr;
       }
            left=head;
            right=head;
            for (i=1;i<=n;i++)
            {
                right=right->next;
            }
            if (right==NULL)
            {
                head=head->next;
                return head;
            }
            while (right->next!=NULL)
            {
               left=left->next;
               right=right->next;
            }
            left->next=left->next->next;
            return head;
    }
};

面试题 02.07. 链表相交

这道题目就正常思路来说没有什么难度,我一开始执着于不去计算链表长度,尝试一遍搜索后找出,最后发现有点困难哈,最终还是计算链表长度后对齐,一个个比较,这道题可以明确一点是,链表结点相同指的是地址相同,而不是数值和指针均相同,完全可以存在并行结构,这点需要特别注意。

以下是代码

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int numA,numB,gap,i;
        ListNode *tempA=new ListNode(0);
        ListNode *tempB=new ListNode(0);
        numA=0;
        numB=0;
        tempA=headA;
        tempB=headB;
        while (tempA!=NULL)
        {
            numA++;
            tempA=tempA->next;
        }
         while (tempB!=NULL)
        {
            numB++;
            tempB=tempB->next;
        }
        gap=abs(numA-numB);
         tempA=headA;
        tempB=headB;
        if (numA>numB)
        {
            for (i=1;i<=gap;i++)
            {
                tempA=tempA->next;
            }
        }
        else
        {
            for (i=1;i<=gap;i++)
            {
               tempB=tempB->next;
            }
        }
        while (tempA!=NULL && tempB!=NULL)
        {
            if (tempA==tempB)
            {
                return tempA;
            }
             tempA=tempA->next;
             tempB=tempB->next;
        }
        return NULL;
    }
};

142. 环形链表 II

这道题一开始没仔细想哈哈,直接用了最暴力的方法,让快慢指针在环中相遇,得到环中结点,求出环长,然后根据环长一一判断,当然最后时间就很慢啦。先贴一个最初版本的代码

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow=new ListNode(0);
        ListNode *fast=new ListNode(0);
         ListNode *temp=new ListNode(0);
          ListNode *temp2=new ListNode(0);
        int i,len,test;
        slow=head;
        fast=head;
        test=1;
        len=1;
        if (head==NULL) return NULL;
        while (test==1)
        {
            if (fast->next==NULL)
            {
                return NULL;
            }
            if ( fast->next->next==NULL)
            {
                 return NULL;
            }
            slow=slow->next;
            fast=fast->next->next;
            if (slow==fast)
            {
               temp=slow->next;
               break;
            }
        }
        while (temp!=slow)
        {
            temp=temp->next;
            len++;
        }
        temp=head;
        while (test==1)
        {
            temp2=temp;
            for (i=1;i<=len;i++)
            {
                temp2=temp2->next;
            }
            if (temp2==temp) return temp;
            temp=temp->next;
        }
        return head;
    }
};

后来结合了卡哥的题解思考了一下,我感觉可以把分析过程更加精简一些,可以不拿代数表达式,把整个过程讲成一个故事,首先快慢指针速度设置成1和2同时前进,按照这个速度两个指针相遇在环中一点后,我们让两个指针以速度1同时倒退,自然会同时退到入口处,而之后二人分道扬镳,当一个指针退回原点时,另一个指针相当于走了两段,倒了一段,就和慢指针走一段到达了同一个地方,也就是相遇的结点处,那么我们就知道了,从相遇结点处两个指针同时以速度1出发,两人也会在入口处再次相遇。(感觉会更好理解一点),再放下我修改后的代码,用时明显改善:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow=new ListNode(0);
        ListNode *fast=new ListNode(0);
         ListNode *temp=new ListNode(0);
          ListNode *temp2=new ListNode(0);
        int i,len,test;
        slow=head;
        fast=head;
        test=1;
        len=1;
        if (head==NULL) return NULL;
        while (test==1)
        {
            if (fast->next==NULL)
            {
                return NULL;
            }
            if ( fast->next->next==NULL)
            {
                 return NULL;
            }
            slow=slow->next;
            fast=fast->next->next;
            if (slow==fast)
            {
               temp=slow;
               break;
            }
        }
       while (head!=temp)
       {
           head=head->next;
           temp=temp->next;
       }
       return head;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值