Day_4_算法训练营第四天 | LC24. 两两交换链表中的节点 LC19.删除链表的倒数第N个节点 LC面试题 02.07. 链表相交 LC142.环形链表II

一、提要

        今天是完成了链表部分的学习,主要学习链表各种问题的处理方式,上一篇文章比较简陋因为都放在这里了。首先题目完成部分是四道题目:24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II 都有题目的编号可以从力扣上面查到问中也有超链接。

在这之中有我对题目思路的附录,希望可以帮助到看文章的鼠鼠们,因为在前期只知道做法却不知道做法是怎么来的这个事情真的很痛苦!

(在代码中是做题时的感悟或者标注,在代码之外的是做完题目的感触)

二、题目完成AC代码及做题体悟

这个题目是完全自己完成的首先我并没有想到加入头节点,我直接开始书写循环,但是我发现在第一次的置换过程中,“头”的置换让我头大,并不能统一之后的置换,所以我加入了头节点,让我的题目顺利完成一编AC(测试的主函数也给你写好了,要是理解不了就自己逐步运行)

#include <iostream>
using namespace std;

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 *leadHead = new ListNode(0,head);
        ListNode *tap = leadHead;  
        ListNode *tmp1, *tmp2;

        while(tap->next != nullptr)
        {
            //置换之前的准备通俗点就是找到你要置换的节点
            tmp1 = tap->next; 
            if (tmp1->next == nullptr) break;  //应对基数个节点的处理,自己画图找每次tmp落点,就明白了
            tmp2 = tap->next->next;
            //置换
            tap->next = tmp1->next;
            tmp1->next = tmp2->next;
            tmp2->next = tmp1;
            //向后更新tap
            tap = tap->next->next;
            //cout << leadHead->val << leadHead->next->val << leadHead->next->next->val << leadHead->next->next->next->val << leadHead->next->next->next->next->val<<endl;

        }
        return leadHead->next;
    }
//};

int main(){
    //初始化列表
    ListNode *head = new ListNode(1); ListNode *one = new ListNode(2);    
    ListNode *two = new ListNode(3); ListNode *three = new ListNode(4);
    head->next = one;   one->next = two;    two->next = three;  three->next = nullptr;

    //调用函数
    ListNode* x =  swapPairs(head);

    //打印结果
    cout << x->val << x->next->val << x->next->next->val << x->next->next->next->val <<endl;

    return 0;
}

这个题目入眼比较简单哈只需要处理两个问题,第一我们需要找到要删除的节点的地址,第二便是定位到需要删除的节点并且删除,因为在做第一遍解法的时候没考率到size的大小的正确的判断气死我了NND(真气死我了铁铁,已经想到的问题没有去做导致后面出现BUG,DBUG的时候没有找到),然后我突然想到如果是倒数,还是倒着来的,我为什么不用递归呢,写完了想发到题解里卖弄一下,结果发现早已经有人这么做了,这个是真的很气!!!没装上。。。。

1

/*
19. 删除链表的倒数第 N 个结点
已解答
中等
相关标签
相关企业
提示
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

 

示例 1:


输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:

输入:head = [1], n = 1
输出:[]
示例 3:

输入:head = [1,2], n = 1
输出:[1]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
 

进阶:你能尝试使用一趟扫描实现吗?
*/

#include <iostream>
using namespace std;

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) {
        //找到目标位置
        int size = 0;   ListNode *tap = head;
        while (tap->next != nullptr)
        {
            size++;
            tap = tap->next;
        }   size++;
        
        //定位到删除位置的前一个并开始删除
        ListNode *new_head = new ListNode(0,head);
        tap = new_head; int num = size - n; int count = 0;
        while (count != num+1 && size != 0)
        {
            if(num == count){
                ListNode *tmp = tap->next;
                tap->next = tap->next->next;
                delete tmp;
            }
            count++;
            tap = tap->next;    
        }
        return new_head->next;
    }
//};

int main(){
    //初始化列表
    ListNode *head = new ListNode(1);
    ListNode *one = new ListNode(2);    
    ListNode *two = new ListNode(3); ListNode *three = new ListNode(4);
    head->next = one;   one->next = two;    two->next = three;  three->next = nullptr;

    //调用函数
    ListNode* x =  removeNthFromEnd(head,1);

    //打印结果
    cout << x->val <<" "<< x->next->val <<" "<< x->next->next->val <<" "<<endl;

    return 0;
}

2

/*
19. 删除链表的倒数第 N 个结点
已解答
中等
相关标签
相关企业
提示
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

 

示例 1:


输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:

输入:head = [1], n = 1
输出:[]
示例 3:

输入:head = [1,2], n = 1
输出:[1]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
 

进阶:你能尝试使用一趟扫描实现吗?
*/

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:
    int cur=0;
    ListNode* removeNthFromEnd(ListNode* head, int n) {
       if(!head) return nullptr;
       head->next = removeNthFromEnd(head->next,n);
       cur++;
       if(n==cur) return head->next;
       return head;
    }
};

这个题目也是用自己的办法解决了hhhhh,鼠鼠我为了省事我就直接套了两个循环遍历一遍就好了hhhhhh结果交上去我是倒数第一名笑死我了,我了个倒数第一!然后当然自己做了优化双层循环就可以思考双指针了!我觉的这句话我自己想的还蛮不错的hhhhh

/*
面试题 02.07. 链表相交
简单
相关标签
相关企业
提示
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:



题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。



示例 1:



输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:



输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:



输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。


提示:

listA 中节点数目为 m
listB 中节点数目为 n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]


进阶:你能否设计一个时间复杂度 O(n) 、仅用 O(1) 内存的解决方案?
*/
#include <iostream>
using namespace std;

struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

//class Solution {
//public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *nmyheadA = new ListNode(0);   nmyheadA->next = headA;
        ListNode *nmyheadB = new ListNode(0);   nmyheadB->next = headB;

        for(ListNode *i = nmyheadA; i != nullptr; i = i->next){
            for(ListNode *j = nmyheadB; j != nullptr; j = j->next){
                if(i == j){
                    return i;
                }
            }
        }
        return 0;
    }
//};

int main(){
    ListNode *A = new ListNode(1);
    ListNode *B = A;
    ListNode * text;
    text = getIntersectionNode(A,B);
    cout << text->val << endl;
    return 0;
}

优化:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != NULL) { // 求链表A的长度
            lenA++;
            curA = curA->next;
        }
        while (curB != NULL) { // 求链表B的长度
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }
        // 求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while (gap--) {
            curA = curA->next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回
        while (curA != NULL) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};
  • 142.环形链表II                                                                                           已完成

这个我是真不会,看了卡哥的视频自己写了一个(点视频给你们超链接了),个人建议别直接看代码真看不懂。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};

三、总结心得

在文中,总结就是学习充实有累,假期加油 !!希望有大佬来评论区指正吧,谢谢。

  • 20
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值