代码随想录算法第四天|Leetcode: 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

​​​​​​​链表详解


​​​​​​​题目链接:24. 两两交换链表中的节点

c++代码(快慢指针)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* freshhead = new ListNode(0);
        freshhead->next = head;
        ListNode* cnt = freshhead;//要改变链表中的东西一般使用虚拟头结点
        while (cnt->next != NULL && cnt->next->next != NULL) {//覆盖链表
            ListNode* a = cnt->next;
            ListNode* b = cnt->next->next;//往后推
            cnt->next = b; 
            a->next = b->next;
            b->next = a;
            cnt = cnt->next->next;
        }
        head = freshhead->next;
        delete freshhead;   
        return head;
    }
};

思路:

三个步骤

  • 步骤一:头指针(虚拟头结点)先要指向2,不然后面找不到头结点了
  • 步骤二:2结点指向1结点
  • 步骤三:1结点指向3结点

顺序不能变,因为第二步可能会用到第三步的东西

代码解释:

           1. cnt->next = b; 
           2. a->next = b->next;
           3. b->next = a;
           4. cnt = cnt->next->next;
  1. 第一个结点(一开始为虚拟头结点)的下一个变成了b
  2. a的下一个变成了b的下一个
  3. b的下一个变成了a
  4. 往后走两个,别名变化(但空间与下面指向相同)



题目链接:19. 删除链表的倒数第 N 个结点

c++暴力解法(双指针二刷再看)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* freshhead = new ListNode(0);
        freshhead->next = head;
        ListNode* cur = freshhead;
        int len = 0;
        while (cur->next != NULL) {
            len++;
            cur = cur->next;
        }
        int gap = len -n;
        cur = freshhead;
        while (gap--) {
            cur = cur->next;
        }
        ListNode* snode = cur->next;
        cur->next = cur->next->next;
        delete snode;
        

        head = freshhead->next;
        delete freshhead;
        return head;
    }
};

思路:

  1. 先算出整个链表的长度
  2. 与n相减得到正序删除的index
  3. 然后就可以用前面学的删除结点了(虚拟头结点)

代码:

cur取别名储存当前位置,防止找不到头,更方便,与下面的那块空间一样



题目链接:面试题 02.07. 链表相交

c++代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0;
        int lenB = 0;
        while (curA != NULL) {
          lenA++;
          curA = curA->next;
        }//A长度
        while (curB !=  NULL) {
          lenB++;
          curB = curB->next;
        }//B长度
        curA = headA;
        curB = headB;

        if (lenA < lenB) {
            swap(lenA, lenB);
            swap(curA, curB);//更换两个指向(别名交换)
        }
        int gap = lenA - lenB;//长度差
        while (gap--) {
            curA = curA->next;
        }//让两指针都从相同末尾长度遍历
        while (lenB--) {
            if(curA == curB) {//如果空间相等的话,后面的连接也相等因为链表他们只能包含一个地址,指向一块空间
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;

    }
};

思路:

  • 题目含义:找到后面长度,值相等的一节的第一个指针,所以必须在末尾长度相同的地方开始找.如下curA和curB

步骤

  1. 算出两个链表的长度
  2. 算出长度差,如果curA长度更长就交换两个链表(为后续操作提供便捷)
  3. 让curA往后移到后curB相对的位置遍历(后面都是两个长度),找到指向同个空间的地址(如上述2)
  4. 返回这个地址

代码:

        1.curA = headA;
        curB = headB;

        if (lenA < lenB) {
            swap(lenA, lenB);
            2.swap(curA, curB);//更换两个指向(别名交换)
        }
  • 这段代码开始又为headA,headB取了别名,重置了
  • 交换别名,指向换了
        while (gap--) {
            curA = curA->next;
        }//让两指针都从相同末尾长度遍历
  • 指向(位置)不断后推,直到后面长度为curB时开始比较

为什么curA==curB就行了

因为不存在环,所以当找到一块相同的空间,地址相同,下一块地址也会相同,因为只会指向一个地址



题目链接:142. 环形链表 II

c++代码(双指针)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
            ListNode* slow = head;
            ListNode* fast = head;
            while (fast != NULL && fast->next != NULL) {//判断有没有环,只要每个结点都判断就对了
                fast = fast->next->next;
                slow = slow->next;
                if (fast == slow) {
                    ListNode* index1 = slow;
                    ListNode* index2 = head;
                    while (index1 != index2) {
                       index1 = index1->next;
                       index2 = index2->next;
                    }
                    return index2;
                }
            }
            return NULL;
    }
};

流动图:

思路:-------------------》具体解析链接,下面是精华

  • 判断链表是否有环

定义两个指针slow和fast,都从头指针开始遍历,如果相遇就一定有环,因为fast进入环中就出不去了,一直转圈。

   while (fast != NULL && fast->next != NULL) {//判断有没有环,出去了就没环

  • 如果有环,如何找到这个环的入口

          

 只要求出一个快指针在相遇点,慢指针在起点他们相遇(一定在入口相遇)走的长度就是要求的x了

步骤

  1. 两个指针都从起点开始,找到相遇点位置
  2. 快指针在相遇点出发,慢指针在起点出发,求出慢指针走的路

代码

            while (fast != NULL && fast->next != NULL)
  • 看有没有环

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值