代码随想录算法训练营第四天 | 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点 ,02.07. 链表相交,142.环形链表II

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

初见:因为这题可以用多个指针来简化难度,所以便想了个双指针和两个临时指针的解,但又一次没有简化头结点和非头结点的解

思路:

1. 贴个图容易理解

代码:
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode();
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        //如果while条件为 || ,若cur->next 为空,将会访问cur->next->next,将会报错:访问空指针
        //为&&,将会再cur->next 不为空,才会访问next 此时无论next是否为空都不影响
        while(cur->next != nullptr && cur->next->next != nullptr)
        {
            ListNode* t1 = cur->next;
            ListNode* t2=  cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = t1;
            t1->next = t2;
            cur = cur->next->next;
        }
        return dummyHead->next;
    }
};

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

初见:这题可以用双循环解决,但难的是用一次循环解决
思路:

1. 用双指针解决

2. fast = slow + n + 1,所以要fast先走n+1步

代码:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0, head);
        ListNode* fast = dummyHead;
        ListNode* slow = dummyHead;
        //使fast运行n + 1步,然后和slow同时遍历,就可以到n结点的前一个结点
        //fast = slow + n + 1; 所以先让fast 走n+1步再同时前进
        while(n--)
        {
            fast = fast->next;
        }
        fast = fast->next;
        //因为不知道什么时候是尾结点,所以当fast 为 nullptr时才知道,而循环停止开始删除
        while(fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
        }
        slow->next = slow->next->next;
        return dummyHead->next;
    }
};

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

初见:完全没思路,感觉算法题考的是数学了

思路:

1.看视频有思路了:即两链表若有相交结点,则后面的链表长度一致。所以当他们相减时得长度n,较长的链表的指针往前移动n位,这样两个链表的指针同时移动就可以遇到相交点

代码:
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr) return nullptr;
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        //求出两个链表的长度
        while(curA != nullptr)
        {
            curA = curA->next;
            lenA++;
        }
        while(curB != nullptr)
        {
            curB = curB->next;
            lenB++;
        }
        //链表长相减就可以得到什么位置开始可以得到相交结点
        if(lenA > lenB)
        {
            curA = headA;
            curB = headB;
            for(int n = lenA - lenB; n > 0; n--)
            {
                curA = curA->next;
            }
        }
        else if(lenB >= lenA)
        {
            curA = headA;
            curB = headB;
            int n = lenB - lenA;
            for(n; n > 0; n--)
            {
                curB = curB->next;
            }
        }
        //一起递进比较,若指针一样则说明该结点为相交结点
        while(curA != curB)
        {
            curA = curA->next;
            curB = curB->next;
            if(curA == nullptr || curB == nullptr) return nullptr;
        }
        return curA;
    }
};

题目四:142. 环形链表 II

初见:想了一会,决定使用循环遍历的想法,这样时间较长

思路:

1. 又一次考数学

2. 当快慢指针相遇一次时,慢指针从头出发,与快指针同时移动一位则可以在环的第一个结点相遇

代码:
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //创建快慢指针
        ListNode* slow = head;
        ListNode* fast = head;
        //当相遇两次时,快慢指针一定在环的第一个结点相遇
        while(fast != nullptr && fast->next != nullptr)
        {
            fast = fast->next->next;
            slow = slow->next;
            //第一次相遇
            if(slow == fast) 
            {
                //第二次相遇
                slow = head;
                while(slow != fast)
                {
                    //各走一步
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

总结:能做出来,但与完美的解法总不相同,希望之后可以偶尔相同吧

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值