代码随想录(day4)——链表

1.Leetcode.24 两两交换链表中的结点:

. - 力扣(LeetCode)

       本题较为简单,在题干中可以看到,系统给定的样例存在空链表,因此,为了避免空链表造成的访问错误,本题也采用人为添加哨兵位头结点的方式。例如对于图中给出的链表,在加上哨兵位头结点后,链表的结构可以表示如下:

对于题目中的要求,即交换结点,可以通过下面的动作完成:

(注:完成交换结点的方法有多种,文章暂提供一种)

首先保存第一,二个结点,并且将这两个结点的地址用两个指针变量tmp1,tmp2保存。

在建立号变量后,首先建立第一个结点和第三个结点的练习,即:

然后再建立tmp2,tmp1的联系:

最后建立哨兵位头结点和tmp2结点的联系,即:

对于上述的图形稍加整理,即:

       在演示了上述过程后,不难看出,如果想要交换两个结点需要在这两个结点中,靠前一个结点的前一个结点最为起始结点开始操作,对于上述链表,如果想要对3,4结点进行操作,则需要将1作为起始结点。

       因此,对于循环的判定条件也可以直接得出,对于上述链表,当对3,4结点操作后,下一次进行操作的起始结点的位置在链表中的第4结点。由于在4后不存在结点,因此可以将检测起始结点的下一个结点是否为空作为循环是否结束的判定条件。

      但是,这种情况只适用于链表中的结点为偶数个。对于链表中结点为奇数个的情况,例如在上述给出的链表中再添加一个结点,即:

按照上面所说,在交换完3,4结点后,进行下一次交换操作的起始结点应该为链表中的第四个结点。因此,对于链表中结点个数为奇数个的情况,应该检查结点的下下个结点是否为空。

     代码如下:

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

       while(cur->next != nullptr && cur->next->next != nullptr)
       {
        ListNode* tmp1 = cur->next->next;
        ListNode* tmp2 = cur->next;

         tmp2->next = tmp1->next;
         tmp1->next = tmp2;
         cur->next = tmp1;
         cur = cur->next->next;
       }

       return phead->next;
       }
};

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

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

       题目难度较低,为了删除链表中的倒数第N个结点,首先需要找到链表中倒数第N个结点。为了消除空链表对于链表遍历带来的影响,需要人为加上哨兵位头结点。在寻找目标结点时,只需要先定义两个指针变量fast,slow,让fast先向前走N步,再令fast,slow一起向后遍历,直到fast为空。具体可以用下面的图片进行表示:

但是这样只是可以找到目标结点,并不能达到删除结点的目的。为了达成删除结点的目的,需要找到目标结点的前一个结点。因此,可以让fast结点在最开始走N+1步,即:

再让两个结点一起向后进行遍历,即:

最后在进行删除结点的操作,对于如何删除结点原理过于简单,因此不过多叙述,只给出代码:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {

        ListNode* phead = new ListNode(0);
        phead->next = head;
        ListNode* fast = phead;
        ListNode* slow = phead;
        
        int n1 = n+1;
        while(n1--)
        {
            fast = fast->next;
        }

        while(fast != nullptr)
        {
            fast = fast->next;
            slow = slow->next;
        }

        ListNode* tmp = slow->next->next;
       
        slow->next = tmp;
        

        return phead->next;

    }
};

3. 面试题.02.07 链表相交: 

面试题 02.07. 链表相交 - 力扣(LeetCode)

原理也较简单,首先创建两个用于遍历的指针curA,curB,遍历一遍两个链表,统计两个链表的长度,然后在创建变量span用于计算两个链表长度的差值。在比较两个链表的长度,让长的链表的头结点先向前遍历span次,最后两个链表一起向后遍历,并且比较此时结点的指针是否相同即可。对应代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

        ListNode* curA = headA;
        ListNode* curB = headB;

        int Asum = 0,Bsum = 0;

        while(curA != nullptr)
        {
            curA = curA->next;
            Asum += 1;

        }

        while(curB != nullptr)
        {
            curB = curB->next;
            Bsum += 1;
        }

        int span = 0;
       span = abs(Asum-Bsum);

        if(Asum > Bsum)
        {
            while(span--)
            {
                headA = headA->next;
            }
        }
        else
        {
            while(span--)
            {
                headB = headB->next;
            }
        }

        while(headA != nullptr)
        {
            if(headA == headB)
            {
                return headA;
            }

            headA = headA->next;
            headB = headB->next;
        }

        return 0;
        
    }
};

4. Leetcode.142 环形链表Ⅱ:

. - 力扣(LeetCode)

对于本题,难点主要在于对于一个关系式的证明,在之前的文章LeetCode.141,142——环形链表,环形链表Ⅱ-CSDN博客给出了详细的推理以及证明。本处只给出代码:
 

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {

        ListNode* slow = head;
        ListNode* fast = head;

        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast ->next->next;

            if(slow == fast)
            {
                ListNode* meet = slow;
                while(head != meet)
                {
                    head = head->next;
                    meet = meet->next;
                }

                return head;
            }

        }
        return NULL;
        
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

起床写代码啦!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值