C语言中链表经典面试题目

简介: 链表分割链表的回文结构 相交链表

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

链表分割

链表的回文结构

相交链表


 

链表分割

描述

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

自测输入:

       {1,1,3,2,4},2

实际输出

       {1,1,3,2,4}

自测输入:

       {1,1,3,1,4},2

实际输出

       {1,1,1,3,4}

解题思路:

整体思路是,创建两个头指针head和phead,head连接小于x的节点,phead连接大于等于x的节点,最后head连接的尾节点指向phead连接的头节点。

1. class Partition
2. {
3. public:
4. ListNode* partition(ListNode* pHead, int x) 
5.     {
6. if(pHead==NULL)
7.         {
8. return NULL;
9.         }
10. // write code here
11.         ListNode* head=NULL;
12.         ListNode* n1=NULL;
13.         ListNode* phead=NULL;
14.         ListNode* n2=NULL;
15.         ListNode* cur=pHead;
16. while(cur)
17.         {
18. if(cur->val<x)
19.             {
20. if(head==NULL)
21.                 {
22.                     head=n1=cur;
23.                 }
24. else
25.                 {
26.                     n1->next=cur;
27.                     n1=n1->next;
28.                 }
29.                 cur=cur->next;
30.             }
31. else
32.             {
33. if(phead==NULL)
34.                 {
35.                     phead=n2=cur;
36.                 }
37. else
38.                 {
39.                    n2->next=cur;
40.                    n2=n2->next;
41.                 }
42.                 cur=cur->next;
43.             }
44.         }
45. if(n2!=NULL)
46.         {
47.             n2->next=NULL;
48.         }
49. if(head==NULL)
50.         {
51. return phead;
52.         }
53.         n1->next=phead;
54. return head;
55.     }
56. };

链表的回文结构

描述

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

1->2->2->1

返回:true

解题思路:

找到链表的中间节点,然后将中间节点包括以后的节点进行逆置,逆置后得到一个头指针,然后依次判断原头指针连接的节点的值和现在得到的头指针连接的节点的值进行比较。这里不需要担心,链表的节点数的奇偶性。

1. #include <cstddef>
2. class PalindromeList {
3. public:
4. bool chkPalindrome(ListNode* A)
5.      {
6. // write code here
7.         ListNode* cur=A;
8. int count =0;
9. while(cur)
10.         {
11.             cur=cur->next;
12.             count++;
13.         }
14. int num=count/2;
15.         ListNode* tail=A;
16.         ListNode* prev=NULL;
17.         ListNode* head=NULL;
18.         ListNode* n1=A;
19. while(num)
20.             {
21.                 num--;
22.                 tail=tail->next;
23.             }
24.             n1=tail;
25.             prev=tail->next;
26. while(n1)
27.             {
28.                 n1->next=head;
29.                 head=n1;
30.                 n1=prev;
31. if(prev!=NULL)
32.                 {
33.                     prev=prev->next;
34.                 }
35.             }
36. while(head)
37.             {
38. if(A->val!=head->val)
39.                 {
40. return false;
41.                 }
42.                 head=head->next;
43.                 A=A->next;
44.             }
45.             tail=NULL;
46. return true;
47.     }
48. };
49. 
50. 
51. 这里是将原来的,找中间节点和逆置的函数进行复用
52. // #include <cstddef>
53. // class PalindromeList {
54. // public:
55. // struct ListNode* reverseList(struct ListNode* head)
56. // {
57. //     if(head==NULL)
58. //     {
59. //         return NULL;
60. //     }
61. //     struct ListNode* n1=NULL;
62. //     struct ListNode* n2=head;
63. //     struct ListNode* n3=head->next;
64. //     while(n2)
65. //     {
66. //         n2->next=n1;
67. //         n1=n2;
68. //         n2=n3;
69. //         if(n3!=NULL)
70. //         {
71. //             n3=n3->next;
72. //         }
73. //     }
74. //     return n1;
75. // }
76. // struct ListNode* middleNode(struct ListNode* head)
77. // {
78. //     struct ListNode* cur=head;
79. //     int count=0;
80. //     while(cur)
81. //     {
82. //         cur=cur->next;
83. //         count++;
84. //     }
85. //     int num=count/2;
86. //     cur=head;
87. //     while(num--)
88. //     {
89. //         cur=cur->next;
90. //     }
91. //     return cur;
92. // }
93. // bool chkPalindrome(ListNode* A)
94. //    {
95. //         // write code here
96. //         ListNode* mid=middleNode(A);
97. //         ListNode* remid=reverseList(mid);
98. //         while(remid)
99. //         {
100. //             if(A->val!=remid->val)
101. //             {
102. //                 return false;
103. //             }
104. //             A=A->next;
105. //             remid=remid->next;
106. //         }
107. //         return true;
108. //    }
109. // };

相交链表

 

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

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

CDC3B817-6ADF-4852-B2F2-541E1DF67D03.png

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

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

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headAheadB传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案

 

示例 1:

214D2CC8-56F9-4AC8-9972-7BB86683298D.png

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3

输出:Intersected at '8'

解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。

从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。

在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

 

示例 2:

6672629F-9563-43D8-975D-B0B656CCCCB6.png

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1

输出:Intersected at '2'

解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。

从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。

在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

8D3C3149-8D7D-4ACD-8266-A3477A3DB40A.png

输入: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
  • 1 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listAlistB 没有交点,intersectVal0
  • 如果 listAlistB 有交点,intersectVal == listA[skipA] == listB[skipB]

 

进阶:你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?

解题思路:

判断两个链表是否相交的关键在于,两个链表的尾节点是否相等(这里指的是为节点的地址,而不是值),相等的话,则两个链表必定相交。如果相交的话,就需要找交点,找交点有两种方法,第一种(暴力求解):A链表所有节点跟B链表的所有节点比较一遍,相等的就是交点,但是时间复杂度为O(N*M)。第二种:分别得到两个链表的长度LA和LB,长的先走abs(LA-LB)步,然后两个同时走,第一个相等的就是交点。

1. //判断链表是否相交,重点在于判断节点的地址是否相等
2. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
3. {
4. struct ListNode* tail1=headA;
5. struct ListNode* tail2=headB;
6. int lenA=1,lenB=1;
7. while(tail1->next)
8.   {
9.       tail1=tail1->next;
10.       lenA++;
11.   }
12. while(tail2->next)
13.   {
14.       tail2=tail2->next;
15.       lenB++;
16.   }
17. //如果尾节点不相等,一定不相交
18. if(tail1!=tail2)
19.   {
20. return NULL;
21.   }
22. //长先走差距步
23. int gap=abs(lenA-lenB);
24. struct ListNode* longList=headA;
25. struct ListNode* shortList=headB;
26. if(lenA<lenB)
27.   {
28.       longList=headB;
29.       shortList=headA;
30.   }
31. while(gap--)
32.   {
33.       longList=longList->next;
34.   }
35. while(longList!=shortList)
36.   {
37.       longList=longList->next;
38.       shortList=shortList->next;
39.   }
40. return longList;
41. }

 

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸  



相关文章
|
5天前
|
C语言
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
|
3天前
|
运维 Linux Docker
Docker笔记(个人向) 简述,最新高频Linux运维面试题目分享
Docker笔记(个人向) 简述,最新高频Linux运维面试题目分享
|
3天前
|
程序员 Python
Job for supervisor,2024年最新b站面试题目
Job for supervisor,2024年最新b站面试题目
|
3天前
|
存储 缓存 JavaScript
web前端常见的面试题汇总(一),web前端面试题目
web前端常见的面试题汇总(一),web前端面试题目
|
3天前
|
Web App开发 JavaScript Android开发
webRTC(十五),2024最新Android中级面试题目汇总解答
webRTC(十五),2024最新Android中级面试题目汇总解答
|
4天前
|
前端开发 JavaScript 开发工具
4(1),阿里面试官,前端开发面试题目
4(1),阿里面试官,前端开发面试题目
|
4天前
|
JavaScript 前端开发 Go
经典面试题目
经典面试题目
10 0
|
5天前
|
算法 C语言
C语言易混淆、简单算法、结构体题目练习、常见关键字总结-2
C语言易混淆、简单算法、结构体题目练习、常见关键字总结
|
5天前
|
算法 编译器 API
C语言易混淆、简单算法、结构体题目练习、常见关键字总结-1
C语言易混淆、简单算法、结构体题目练习、常见关键字总结
|
5天前
|
存储 Java 编译器
链表面试题的总结和思路分享
链表面试题的总结和思路分享