算法训练营第4天

题目链接 24. 两两交换链表中的节点 & 19.删除链表的倒数第N个节点 & 面试题 02.07. 链表相交 & 142.环形链表II
今日学习的文章链接和视频链接 24. 两两交换链表中的节点 & 19.删除链表的倒数第N个节点 & 面试题 02.07. 链表相交 & 142.环形链表II

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

自己看到题目的第一想法

看完代码随想录之后的想法

取要翻转的2个节点的前1个节点为cur,这样可以操作后两个节点和确定循环终止条件。
当链表为空时,和偶数节点的链表一样被处理,因为虚拟节点很好地统一了这种特殊情况。
在交换元素的时候,按顺序进行操作较好。

// 时复 O(n),空复 O(1)
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(0, head);
        ListNode* cur = dummy_head, * tmp_front = nullptr, * tmp_back = nullptr;

        while (cur->next != nullptr && cur->next->next != nullptr) {
            tmp_front = cur->next;
            tmp_back = cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = tmp_front;
            tmp_front->next = tmp_back;
            cur = tmp_front; // cur = cur->next->next;
        }

        return dummy_head->next;
    }
};

自己实现过程中遇到哪些困难

看完视频后实现,没有困难

今日收获,记录一下自己的学习时长

自己动手画画,逻辑清楚后写代码真的很爽

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

自己看到题目的第一想法

我的第一想法,两遍循环:

// 时复 O(n),空复 O(1)
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        int sz = 0;
        ListNode* dummy_head = new ListNode(0, head);
        ListNode* i = head, * pre = nullptr, * tmp = nullptr;
        
        while(i != nullptr) sz++, i = i->next;

        i = head, pre = dummy_head;
        while (sz-- > n) {            
            pre = i;
            i = i->next;          
        }
        pre->next = i->next;
        tmp = i;
        delete tmp;

        return dummy_head->next;
    }
};

看完代码随想录之后的想法

快慢双指针,一遍循环:

// 时/空复 O(n)/O(1)
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy_head = new ListNode(0, head);
        ListNode* i = head, * pre = dummy_head, * fast = dummy_head, * slow = dummy_head;
        
        while(n--) {            
            fast = fast->next;          
        }
        
        while(fast != nullptr) {
            fast = fast->next;
            pre = slow;
            slow = slow->next;
        }

        pre->next = slow->next;
        delete slow;

        return dummy_head->next;
    }
};

自己实现过程中遇到哪些困难

注意循环结束条件,同时模拟一遍操作,因为此时不熟悉。

今日收获,记录一下自己的学习时长

  1. 链表的遍历和删除
  2. 双指针的使用

面试题 02.07. 链表相交

自己看到题目的第一想法

题干很迷,输入到底是啥?
第一想法+提示:比较的是指针相等而不是数值,时空复杂度O(n)O(1)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        for(ListNode* i = headA; i != NULL; i = i->next) 
            for (ListNode* j = headB; j != NULL; j = j->next) 
                if (i == j) return i;

        return NULL;
    }
};

看完代码随想录之后的想法

4步:

  1. 求出2个链表的长度
  2. 求出2个链表长度差值,确定最长者,后续操作需要移动其指针
  3. 2个链表形式上尾端对齐(根据题干要求),同时将指针对齐
  4. 2个链表的指针同时移动,同时比较是否相等
    随想录版本:
// 时空复杂度O(n)O(1)
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int headA_length = 0, headB_length = 0, diff = 0;
        ListNode* curA = headA, * curB = headB;

        for (ListNode* i = headA; i != NULL; i = i->next) headA_length++;
        for (ListNode* i = headB; i != NULL; i = i->next) headB_length++;
        
        if (headA_length < headB_length) {
            swap(headA_length, headB_length);
            swap(headA, headB);
            swap(curA, curB);
        }
        diff = headA_length - headB_length;

        while (diff--) curA = curA->next;

        while (curA != NULL && curB != NULL) {
            if (curA == curB) return curA;
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};

自己实现过程中遇到哪些困难

题干难以理解,原来就是如图所示,将链表后端对齐

今日收获,记录一下自己的学习时长

链表操作和题干理解

142.环形链表II

自己看到题目的第一想法

两层for循环但是内存会超时。

看完代码随想录之后的想法

单指针是不可以的,因为总会陷入死循环。快慢双指针可以,在直线上快慢双指针不会相遇;
但是在环中,设置fast步长为2,slow步长为1,会相遇的。不要和跑步套圈看作同一种,因为此处为离散的,跑步是连续的。fast相对slow的速度为1,所以fast不会跳过slow。实际上slow在进入环的第一圈就被追上了,因为fast速度是其2倍同时不会跳过slow
学自随想录:

// 时空复杂度O(n)O(1)
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast = head, *slow = head;

        while(fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow) {
                ListNode *index1 = fast, *index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return NULL;
    }
};

自己实现过程中遇到哪些困难

整个逻辑都是比较复杂的,不仅需要模拟也需要自己列公式。

今日收获,记录一下自己的学习时长

环形链表

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邓俊辉教授是计算机科学与技术领域著名的教育家和研究者。他在清华大学担任教授,并负责计算机算法与理论方向的研究和教学工作。邓俊辉教授是中国计算机学会副理事长、国际著名科技出版社Springer中国系列丛书主编、IEICE China Communications主编、Journal of Internet Technology编委、《数据结构与算法教程》作者等。 在邓俊辉教授的指导下,他办了多次Dijkstra算法训练营,旨在培养学生对于算法学习的兴趣与能力。Dijkstra算法是一种用于图论中求解最短路径问题的经典算法,具有广泛的应用领域,如路由算法、网络规划和GPS导航系统等。在训练营中,邓俊辉教授通过讲解算法的原理和思想,引导学生进行编程实践和案例分析,帮助他们深入理解Dijkstra算法的应用场景与实际解决问题的能力。 邓俊辉教授所组织的Dijkstra算法训练营受到了广大学生的欢迎和积极参与。通过训练营的学习,学生不仅可以掌握Dijkstra算法的具体实现过程,还能了解算法设计的思路和应用的局限性。在训练营中,学生还可以与同学们进行交流和合作,共同解决实际问题,促进彼此的学术成长和人际交往能力的培养。 总之,邓俊辉的Dijkstra算法训练营为学生提供了一个系统、全面学习算法知识的平台,帮助他们培养解决实际问题的能力和思维方式。通过这样的培训,学生不仅能在学术领域取得更好的成绩,还可以为将来的职业发展打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值