五个经典链表OJ题带你进阶C++链表篇
目录
- 反转单链表
- 返回链表中间节点的位置
- 合并两个有序链表
- 判断链表中是否有环
- 判断环形链表进入的节点
反转单链表
题目1:给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
题目来源:力扣
思路一: 翻转指针方向,首先我们要有三个指针,这个就不展示代码了,逻辑过程如下:
思路二:头插方法,我们把每个节点拿下来进行头插实现!代码实现如下:
struct ListNode* reverseList(struct ListNode* head) { struct ListNode* cur = head; struct ListNode* newHead = NULL; while (cur) { struct ListNode* next = cur->next; //头插 cur->next = newHead; newHead = cur; cur = next; } return newHead; }
返回链表中间节点的位置
题目2:给定一个头结点为 head
的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点
题目来源:力扣
思路: 我们使用快慢指针的办法,快指针fast走两步,慢指针slow走一步,这样当fast走完了,slow指针就走到了中间的位置,但是我们要注意,如果链表节点为奇数个则当fast为NULL就应该结束循环,如果链表节点为偶数个则当fast->next为NULL则结束循环!思路解析,代码实现如下:
struct ListNode* middleNode(struct ListNode* head) { struct ListNode* slow = head, * fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } return slow; }
合并两个有序链表
题目3:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
题目来源:力扣
思路:首先我们要判断两个链表是否为空,如果为空则返回另一个链表!接着我们需要定义两个指针头指针head和一个尾指针tail,接着我们比较list1->val是否大于list2->val然后进行链接链表的操作,并且当其中一个链表为空则跳出循环,我们则需要在循环外再次判断是哪个链表为空导致跳出的循环,并且最后把不为空的链表链接在后面!最后返回头指针head!
建议小伙伴们看着这个思路尝试着自己写一下,可以参考如下代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { if (list1 == NULL) return list2; if (list2 == NULL) return list1; struct ListNode* head = NULL, * tail = NULL; if (list1->val < list2->val) { head = tail = list1; list1 = list1->next; } else { head = tail = list2; list2 = list2->next; } while (list1 != NULL && list2 != NULL) { if (list1->val < list2->val) { //尾插 tail->next = list1; list1 = list1->next; } else { tail->next = list2; list2 = list2->next; } tail = tail->next; } if (list1) tail->next = list1; if (list2) tail->next = list2; return head; }
判断链表中是否有环
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
题目来源:力扣
思路: 我们使用快慢指针的方法,让fast指针一次走两步,slow指针一次走一步,当链表有环的时候,当slow进入环了,fast就开始追slow,假设fast跟slow的距离为N,每走一次fast跟slow的距离就会缩小一步,也就是N-1,N-2,N-3,N-4,直到N为0 fast就追上slow了!代码实现如下:
bool hasCycle(struct ListNode *head) { struct ListNode* fast = head; struct ListNode* slow = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; }
判断环形链表进入的节点
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
题目来源:力扣
思路:我们还是用跟上面一样的快慢指针的方法,但是在后面,一个指针从相遇点meet开始走,一个指针从链表头head开始走,他们会在入口点相遇!图解,代码参考见下:
bool hasCycle(struct ListNode *head) { struct ListNode* fast = head; struct ListNode* slow = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; }