Ubuntu 20.04 下 RealSense 驱动安装与 realsense-viewer 配置全指南
2026/9/28 1:03:23
83. 删除排序链表中的重复元素
给定一个已排序的链表的头head,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。
示例 1:
输入:head = [1,1,2]输出:[1,2]
示例 2:
输入:head = [1,1,2,3,3]输出:[1,2,3]
提示:
[0, 300]内-100 <= Node.val <= 100没有难度,秒掉了,没有什么考察的难点。
/** * 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* deleteDuplicates(ListNode* head) { if (head == nullptr){ return nullptr; } ListNode*dummy = new ListNode(0); dummy -> next = head ; ListNode* cur = head ; while(cur -> next != nullptr){ if (cur -> next -> val == cur -> val){ cur -> next = cur -> next -> next ; }else{ cur = cur -> next ; } } head = dummy -> next; delete dummy; return head ; } };1669. 合并两个链表
给你两个链表list1和list2,它们包含的元素分别为n个和m个。
请你将list1中下标从a到b的全部节点都删除,并将list2接在被删除节点的位置。
下图中蓝色边和节点展示了操作后的结果:
请你返回结果链表的头指针。
示例 1:
输入:list1 = [10,1,13,6,9,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]输出:[10,1,13,1000000,1000001,1000002,5]解释:我们删除 list1 中下标为 3 和 4 的两个节点,并将 list2 接在该位置。上图中蓝色的边和节点为答案链表。
示例 2:
输入:list1 = [0,1,2,3,4,5,6], a = 2, b = 5, list2 = [1000000,1000001,1000002,1000003,1000004]输出:[0,1,1000000,1000001,1000002,1000003,1000004,6]解释:上图中蓝色的边和节点为答案链表。
提示:
3 <= list1.length <= 1041 <= a <= b < list1.length - 11 <= list2.length <= 104居然自己写出来了!!!今天两题都是自己手敲出来的!!!
/** * 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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { int counter = 0 ; ListNode* dummy = new ListNode(0); dummy -> next = list1; ListNode* cur = list1; while(cur -> next!= nullptr){ counter ++; if(counter == a ){ ListNode* p = cur -> next; for(int i = a ; i < b + 1 ;++i){ p = p -> next ; } cur -> next = list2; while(list2 -> next!= nullptr){ list2 = list2 -> next; } list2 -> next = p ; }else{ cur = cur -> next; } } dummy -> next = list1; delete dummy; return list1; } };但其实我觉得自己写的和史没区别,思路很简单粗暴:
1.list1遍历到a,同时有counter计数下标
2.遍历到a以后存储要连接的节点,这段尾巴连接list2的头
3.a一直往下遍历到b。list2的尾巴连接到list1的剩余部分
可喜可贺,这次没有依赖ai,没有依靠题解。但至少自己写通过了!
但是,我知道自己写的只是通过的程度,时空复杂度没考虑,效率没考虑,哑节点也是按照经验放觉得直接操作要删除的list的head不安全,实际上的理解不是很深。
用ai老师来给我指出一点优化和值得反思的地方,尽管这对我来说是一次成功!
--------
首先要恭喜你!能独立完成这两道链表题真的非常棒,这是实实在在的进步。接下来我会针对你写的代码,从优化思路、代码健壮性、空间 / 时间效率以及核心知识点理解几个方面给你分析和建议。
/** * 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* deleteDuplicates(ListNode* head) { // 空链表直接返回 if (head == nullptr) { return nullptr; } // 直接使用原链表头节点,无需dummy ListNode* cur = head; while (cur->next != nullptr) { if (cur->val == cur->next->val) { // 保存要删除的节点,避免内存泄漏(可选,但养成好习惯) ListNode* temp = cur->next; cur->next = cur->next->next; delete temp; // 释放重复节点的内存 } else { cur = cur->next; } } return head; } };for循环从 a 遍历到 b+1,这会导致重复遍历;而且外层的while循环会遍历整个 list1,实际上我们只需要找到关键节点即可。cur->next!= nullptr的判断可能会导致如果 a 是最后一个节点时出现问题(虽然题目约束 a <= b < list1.length-1,不会触发,但代码鲁棒性不足)。/** * 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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { // 1. 找到list1中第a-1个节点(要插入list2的前驱节点) ListNode* preA = list1; for (int i = 0; i < a - 1; ++i) { preA = preA->next; } // 2. 找到list1中第b+1个节点(要插入list2的后继节点) ListNode* postB = preA; for (int i = a - 1; i < b + 1; ++i) { postB = postB->next; } // 3. 找到list2的尾节点(不修改原list2指针) ListNode* list2Tail = list2; while (list2Tail->next != nullptr) { list2Tail = list2Tail->next; } // 4. 拼接链表 preA->next = list2; // 前驱节点连接list2头 list2Tail->next = postB; // list2尾连接后继节点 return list1; } };list2Tail遍历 list2,保留原list2指针不变,符合良好的编程规范。你提到对 dummy 节点理解不深,这里给你清晰的总结:
必须使用的场景:
不需要使用的场景:
继续保持这个势头!你已经能独立解决链表问题,接下来可以关注代码的效率和规范性,你的进步会更快。