暑期LeetCode打卡——Week1,链表

Leetcode 专栏收录该内容
13 篇文章 0 订阅

刷题时间: 2019/04/20 –
主播:yxc(闫雪灿)
视频链接: https://v.douyu.com/show/jwzOvpw6DDEWZVRm

题号题目链接
147Insertion Sort Listhttps://leetcode.com/problems/insertion-sort-list/
138Copy List with Random Pointerhttps://leetcode.com/problems/copy-list-with-random-pointer/
86Partition Listhttps://leetcode.com/problems/partition-list/
30Substring with Concatenation of All Wordshttps://leetcode.com/problems/substring-with-concatenation-of-all-words/
24Swap Nodes in Pairshttps://leetcode.com/problems/swap-nodes-in-pairs/
19Remove Nth Node From End of Listhttps://leetcode.com/problems/remove-nth-node-from-end-of-list/
83Remove Duplicates from Sorted Listhttps://leetcode.com/problems/remove-duplicates-from-sorted-list/
206Reverse Linked Listhttps://leetcode.com/problems/reverse-linked-list/
92Reverse Linked List IIhttps://leetcode.com/problems/reverse-linked-list-ii/
61Rotate Listhttps://leetcode.com/problems/rotate-list/
143Reorder Listhttps://leetcode.com/problems/reorder-list/
141Linked List Cyclehttps://leetcode.com/problems/linked-list-cycle/
160Intersection of Two Linked Listshttps://leetcode.com/problems/intersection-of-two-linked-lists/
142Linked List Cycle IIhttps://leetcode.com/problems/linked-list-cycle-ii/
109Convert Sorted List to Binary Search Treehttps://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/
82Remove Duplicates from Sorted List IIhttps://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
148Sort Listhttps://leetcode.com/problems/sort-list/
234Palindrome Linked Listhttps://leetcode.com/problems/palindrome-linked-list/
237Delete Node in a Linked Listhttps://leetcode.com/problems/delete-node-in-a-linked-list/
328Odd Even Linked Listhttps://leetcode.com/problems/odd-even-linked-list/

在这里插入图片描述
在这里插入图片描述

解题心得

No.147 对链表插入排序 (AC)(划重点)

  • 本题的思路是:从前往后,找到第一个比当前结点大的结点,然后将当前结点插入到它的前面。
  • 本比很容易写出Bug. 第一个需要注意的点是,按照自己的惯常思路和想法,容易出现尾指针没有指向空的问题。 按照yxc的思路写时, 需要特别注意,新建立的虚拟头结点不指向head指针,否者也是Bug,这个可以举一个例子画画图理解。

No.138 复杂链表的赋值 (AC)

  • step1: 在链表每个节点后插入一个它的新建赋值结点;
  • step2: 给新插入的结点赋值random指针的值
  • step3: 从修改链表中把赋值的链表拎出来。并将原链表结构还原。还原原链表非常关键,否则就不是deep copy了,之前程序不能ac就是这个原因。
  • 还有一点是,要看结点的构造函数,在本题中,初始化时,next指针和random指针也需要给定值,否则会报指针错误。

No.86 将链表按照指定规则调整顺序 (AC)

  • 插入位置可能是头结点之前,所以需要建立一个虚拟头结点;
  • 先找到第一个值比target小的结点p,作为插入结点的头,然后新建一个q结点从p之后遍历,并记录他的前驱结点和后继结点。当q结点的值小于target时,将q结点插入到p之后,为了保持位置关系,p结点后移。同时q结点这边的连接关系也需要更新。

No.30 Substring with Concatenation of All Words (AC)

  • 枚举的方法,时间复杂度为O(n* len),循环n次,每次只要判断word_num * word_len的长度即可。

No.24. 成对交换前后两个结点对 (AC)

  • 需要注意的是,pre->1->2->3中,把1指向3, pre指向2之后,好需要将2指向1,不然中间就断了。

No.19 移除链表中的倒数第n和结点 (AC)

  • 链表问题通常存在边界问题,如头结点会被删除,解决这个问题通常是定义一个虚拟头结点,指向真正的头结点。
  • 在本题中,用双指针找到倒数第n个结点,然后删除。整个过程只要扫描一遍。
  • 还有一个边界是删除倒数第0个结点,即不删除,这种情况直接返回即可。

No.83 删除排序链表中的重复元素 (AC)

  • 从前往后遍历,若前后两个元素相等,则删除后者,否者继续往后扫描。

No.206 翻转链表 (AC)

  • 需要记录一个前驱结点和一个后继结点。
  • 最终前驱结点即为翻转链表的新结点。

No.92 翻转链表中指定段 (AC)

  • 头结点也有可能被翻转,因此需要定义一个虚拟头结点。
  • 先定位要翻转的段,翻转完成之后,再链接到原链表中。
  • 最好不要用pre = pre->next; 去更新pre结点,因为链接顺序改变之后,直接这样做很可能会指向其他结点。

No.61 循环数组 (AC)

  • 这道题有两种做法。
  • 第一种方法是单个往前移,需要用一个deque队列存放链表中的元素。
  • 由于k可能比链表长度大,所以被弹出的尾结点在处理完之后再添加到deque队列的对手。
  • 有几个边界特判条件:当链表为空,或链表长度为1,或k为0时都可以直接返回。
  • 第二种方法是整段往前移。这里一定要处理的是k大于链表长度的情况。k对链表长度取模,若为0,则直接返回,否则,移到链表前面。
  • 这两种方法中头结点都可能会被翻转,所以在表头增加一个虚拟结点。

No.143 数字重排序 (AC) 划重点!

  • 本题可以用一个栈辅助操作,需要额外O(n)的空间
  • 更好的方法是,找到中点,将后半部分翻转,然后与前半部分合并。
  • 几个实现细节:1. 将前后两小段的尾结点指向空,方便后边合并。2.合并时容易写错。
  • 假设两个待合并链表为pNode和pPre,
    在这里插入图片描述
    若按照先1后2的方式合并(!错误!),代码如下:
for (int i = num + 1 >> 1; i < num; i++){
        ListNode* pNext = pNode->next;
        pNode->next = pPre;
        pPre = pPre->next;
        pPre->next = pNext; // ERROR! 此时pPre指向的位置已经别改变了
        pNode = pNext;
 }   

正确的方式是先2后1,代码如下:

for (int i = num + 1 >> 1; i < num; i++){
        ListNode* t = pPre->next;
        pPre->next = pNode->next;
        pNode->next = pPre;
        pNode = pNode->next->next;
        pPre = t;
 }  

No.141 判断链表是否有环 (AC)(易错题)

  • 快慢指针来做
  • 本题很容易写出bug,有两个地方值得注意一下:
bool hasCycle(ListNode *head) {
        if (!head) return false;
        ListNode* fast = head->next;
        ListNode* slow = head;
        while(fast != slow){
            /*
            // bug写法
            // 若只有一个元素,那么指针始终无法后移,造成TLE
            // 因此可以将快慢指针分开来后移,这样可以保证慢指针能往后移
             if (fast && fast->next && slow) { // 不加fast,若只有一个元素,会溢出
                fast = fast->next->next;
                slow = slow->next;
            }
            */
            if (fast && fast->next ) { // 若只有一个元素,会溢出
                fast = fast->next->next;
            }
            if (slow) slow = slow->next;
            if(!fast || !slow) return false; 
        }
        return !fast->next ? false : true; // 需要判断是否下一个指针为结尾 
        // 反例: 1,2  -1 这种情况下快慢指针仍可以相等,但并没有形成环,因此需要判断相遇位置是否是尾结点的前一个位置
    }

NO.160 找两个链表的公共结点 (AC) (易错题)

  • 基本思路:双指针把来哥哥链表走两遍,相遇的位置即为交点。
  • 特判边界:1. 两个链表没有交点。这种情况下什么时候跳出循环以及返回什么值需要考虑一下,容易写出bug,详见代码。 2. 两个链表本身就是同一个链表,即从第一个元素起就相同,这种情况需要特判,否则会返回nullptr。

NO.142 寻找循环链表的环入口 (AC)

  • Step1: 快慢指针找到换种的相遇点
  • Step2: 计算环的大小k
  • Step3: 双指针前后相隔k步出发,相遇点即为环的入口。
  • 需要特判的情况: fast->next-next是否存在;环是否存在。若环不存在,则fast || fast->next || slow中一定有个指针会到达nullptr结点,此时直接返回nullptr即可。

No.109 将排序链表转换成平衡搜索二叉树 (AC)

  • 思路类似于根据中序和先序重构二叉树,用递归的方法来做。
  • 在写的时候需要注意满足搜索二叉树的需求,这里很巧,正常写就可以满足。

No.82 将链表中重复的数字全部删除 (AC)

  • 需要记录一个前驱结点和一个cur结点,关键两行代码如下:
while(q){
            while(q && p->next->val == q->val) 
            	q = q->next; // 是判断结点的值相等,不是结点相等,因为结点还有next指针
            	if (p->next->next == q) p = p->next; // 此时是需要指向相同的结点
                else p->next = q;
        }

No. 148 链表排序(归并)(AC)(划重点)

  • 解题思路是: 先对最小的区间进行排序,然后将两个排序子区间合并;然后再向上递归处理。
  • 需要注意的是,每个排好序的小区间需要断开,即末尾要指向nullptr,方便下一步的链表合并。
  • 在将一个小区间划分成两个部分时,可以用快慢指针快速实现。
  • 在链表合并时,最后剩余的而一条链的判断语句是if,不是while,这里写错几次了。

No.234 判断一个链表是否是回文链表 (AC)

  • BUG思路:将整个链表翻转,然后比较翻转前后的链表是否相同。这种做法存在的问题是, 完成翻转之后,原链表的头指针已经不在是原链表的头指针,即只能维持一条链表的完整,不能同时保证翻转前后的链表完整。
  • 改进思路: 将链表后半部分翻转,翻转后比较前后时候是完全相同的。在比较的时候只要处理n/2长度的,这样不管是奇偶都可以解决。

No.237 删除链表中的某个结点 (AC)

  • 当前删除结点的下一个结点为尾结点,则直接将当前结点赋值为nullptr;
  • 将要删除的结点的下一个结点的值赋给当前结点,然后将当前结点的下一个结点删除。

No.328 将原链表中奇数位置的结点放在一起,后面接偶数位置的结点 (AC)

  • 新建两个表头,分别是奇数位置结点和偶数位置结点的表头,然后将原链表中相应结点临界点两个头结点后边,再把偶数头结点链到奇数链表的结尾。特别需要注意的是,偶数链表的为节点需要指向nullptr。否则无法打印出结果,显示TLE。
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏作者

MaggieYue

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值