• 【数据结构与算法】---OJ链表题来源力扣和牛客


    作者:旧梦拾遗186

    专栏:数据结构成长日记

     

    目录

    环形链表

    题解:

     环形链表扩展问题:

    环形链表II

    题解:

     复制带随机指针的链表

    题解:


    环形链表

    环形链表icon-default.png?t=M666https://leetcode.cn/problems/linked-list-cycle/

    给你一个链表的头节点 head ,判断链表中是否有环。

    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

    如果链表中存在环 ,则返回 true 。 否则,返回 false 。

    示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。
    示例 2:

    输入:head = [1,2], pos = 0
    输出:true
    解释:链表中有一个环,其尾部连接到第一个节点。
    示例 3:

    输入:head = [1], pos = -1
    输出:false
    解释:链表中没有环。
     

    提示:

    链表中节点的数目范围是 [0, 104]
    -105 <= Node.val <= 105
    pos 为 -1 或者链表中的一个 有效索引 。
     

    进阶:你能用 O(1)(即,常量)内存解决此问题吗?

    题解:

    思路:带环链表不能遍历。。。我们可以用快慢指针来解决这道题目,快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾

    1. bool hasCycle(struct ListNode *head) {
    2. struct ListNode* slow=head;
    3. struct ListNode* fast=head;
    4. while(fast&&fast->next)
    5. {
    6. slow=slow->next;
    7. fast=fast->next->next;
    8. if(slow==fast)
    9. {
    10. return true;
    11. }
    12. }
    13. return false;
    14. }

     

     环形链表扩展问题:

    【扩展问题】
    为什么快指针每次走两步,慢指针走一步可以?
    假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚
    进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。
    此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情
    况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
    快指针一次走 3 步,走 4 步, ...n 步行吗?

    为什么快指针每次走两步,慢指针走一步可以追上,会不会错过?

    • slow一次走一步,fast一次走三步呢

    • slow一次走一步,fast一次走X步呢

     

     

     

    环形链表II

    给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

    不允许修改 链表。

    示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:返回索引为 1 的链表节点
    解释:链表中有一个环,其尾部连接到第二个节点。
    示例 2:

    输入:head = [1,2], pos = 0
    输出:返回索引为 0 的链表节点
    解释:链表中有一个环,其尾部连接到第一个节点。
    示例 3:

    输入:head = [1], pos = -1
    输出:返回 null
    解释:链表中没有环。
     

    提示:

    链表中节点的数目范围在范围 [0, 104] 内
    -105 <= Node.val <= 105
    pos 的值为 -1 或者链表中的一个有效索引
     

    进阶:你是否可以使用 O(1) 空间解决此题?

    题解:

     

    1. struct ListNode *detectCycle(struct ListNode *head) {
    2. struct ListNode*slow = head,*fast = head;
    3. while(fast && fast->next)
    4. {
    5. slow = slow->next;
    6. fast = fast->next->next;
    7. if(slow == fast)
    8. {
    9. struct ListNode*meet = slow;
    10. while(head!=meet)
    11. {
    12. head = head->next;
    13. meet = meet->next;
    14. }
    15. return meet;
    16. }
    17. }
    18. return NULL;
    19. }

    思路二:转化成相交链表,从相遇点断开后,作为一个链表,另一个链表从头开始,链表开始入环的第一个节点就相当于这两个链表的交点,而找链表的交点就是上面的题目相交链表。

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
    2. {
    3. struct ListNode*curA = headA,*curB = headB;
    4. int LenA = 0,LenB = 0;
    5. while(curA)
    6. {
    7. curA = curA->next;
    8. LenA++;
    9. }
    10. while(curB)
    11. {
    12. curB = curB->next;
    13. LenB++;
    14. }
    15. if(curA != curB)
    16. {
    17. retur NULL;
    18. }
    19. struct ListNode*longlist = headA,*shortlist = headB;
    20. if(LenA
    21. {
    22. longlist = headB;
    23. shortlist = headA;
    24. }
    25. int gap = abs(LenA-LenB);
    26. while(gap--)
    27. {
    28. longlist = longlist->next;
    29. }
    30. while(longlist!=shortlist)
    31. {
    32. longlist = longlist->next;
    33. shortlist = shortlist->next;
    34. }
    35. return longlist;
    36. }
    37. struct ListNode *detectCycle(struct ListNode *head) {
    38. struct ListNode*slow = head,*fast = head;
    39. while(fast && fast->next)
    40. {
    41. slow = slow->next;
    42. fast = fast->next->next;
    43. if(slow == fast)
    44. {
    45. //找到相遇的点
    46. struct ListNode*meet = slow;
    47. struct ListNode*next = meet->next;
    48. //断开
    49. meet->next = NULL;
    50. struct ListNode*enterNode = getIntersectionNode(head,next);
    51. //恢复原来的链表
    52. meet->next = next;
    53. return enterNode;
    54. }
    55. }
    56. return NULL;
    57. }

     复制带随机指针的链表

    复制带随机指针的链表icon-default.png?t=M666https://leetcode.cn/problems/copy-list-with-random-pointer/

     

    给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

    构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

    例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

    返回复制链表的头节点。

    用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

    val:一个表示 Node.val 的整数。
    random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
    你的代码 只 接受原链表的头节点 head 作为传入参数。

    示例 1:

    输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
    输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
    示例 2:

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

    输入:head = [[3,null],[3,0],[3,null]]
    输出:[[3,null],[3,0],[3,null]]
     

    提示:

    0 <= n <= 1000
    -104 <= Node.val <= 104
    Node.random 为 null 或指向链表中的节点。

    题解:

    本题较难。如果我们每个节点都去进行复制,这道题的random我们较难去处理:

    image-20220802144431586

    image-20220802152210269

     

    1. struct Node* copyRandomList(struct Node* head) {
    2. //copy节点
    3. struct Node* cur = head;
    4. struct Node*copy = NULL;
    5. struct Node*next = NULL;
    6. while(cur)
    7. {
    8. //赋值链接
    9. next = cur->next;
    10. copy = (struct Node*)malloc(sizeof(struct Node));
    11. copy->val = cur->val;
    12. cur->next = copy;
    13. copy->next = next;
    14. //迭代
    15. cur = next;
    16. }
    17. //更新copy的random
    18. cur = head;
    19. while(cur)
    20. {
    21. copy = cur->next;
    22. if(cur->random == NULL)
    23. {
    24. copy->random = NULL;
    25. }
    26. else
    27. {
    28. copy->random = cur->random->next;
    29. }
    30. //迭代
    31. cur = cur->next->next;
    32. }
    33. //copy节点解下来链接在一起,恢复原链表
    34. struct Node*copyHead = NULL,*copyTail = NULL;
    35. cur = head;
    36. while(cur)
    37. {
    38. copy = cur->next;
    39. next = copy->next;
    40. //取节点尾插
    41. if(copyTail == NULL)
    42. {
    43. copyHead = copyTail = copy;
    44. }
    45. else
    46. {
    47. copyTail->next = copy;
    48. copyTail = copyTail->next;
    49. }
    50. //恢复原链表
    51. cur->next = next;
    52. cur = next;
    53. }
    54. return copyHead;
    55. }

  • 相关阅读:
    使用uniapp开发时自定义tabbar
    三维模型3DTile格式轻量化在三维展示效果上的重要性分析
    php伪协议 [ACTF2020 新生赛]Include1
    uni-app 之 获取网络列表数据
    YOLOv5 添加 OTA,并使用 coco、CrowdHuman数据集进行训练。
    php实战案例记录(11)unset函数的用法
    web前端设计与开发期末作品 旅游咨询网站 HTML5期末大作业 HTML+CSS旅游社网站5个页面 关于制作网页主题论述
    linux安装telnet遇到的问题
    行秋找工作的记录
    不改平面不加层,微调走线抬电平
  • 原文地址:https://blog.csdn.net/weixin_67900732/article/details/126220720