剑指offer学习笔记(8.3|剑指offer学习笔记:8.3 链表)
面试题56:链表中环的入口解题思路:
【剑指offer学习笔记(8.3|剑指offer学习笔记:8.3 链表)】一个链表中含环,如何找到环的入口
牛客网链接 https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&&tqId=11208&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: // 通过快慢指针判断链表中是否存在环,如果存在环,返回相遇节点,如果不存在环,返回NULL ListNode* meetNode(ListNode* pHead) { if (pHead == NULL) { return pHead; } ListNode* slow = pHead; ListNode* fast = slow->next; if (fast == NULL) { return NULL; } while(slow != NULL && fast != NULL && fast->next != NULL) { if (slow == fast) { return fast; } slow = slow->next; fast = fast->next->next; } return NULL; } ListNode* EntryNodeOfLoop(ListNode* pHead) { // 第一步:找到环中一个点 ListNode* meet = meetNode(pHead); if (meet == NULL) { return NULL; } // 第二步:计算环的长度 int n = 1; ListNode* tmp = meet->next; while(tmp != meet) { tmp = tmp->next; n++; } // 第三步:定义两个指针,指针p2先走n步 ListNode* p1 = pHead; ListNode* p2 = pHead; for(int i = 0; i < n; i++) { p2 = p2->next; } // p1,p2再次相遇之处,就是环的入口 while(p1 != p2) { p1 = p1->next; p2 = p2->next; } return p1; } };
考虑没有环的情况
思路1:双指针法。
首先需要确认环的长度,当确认环的长度n后,让指针p2先于指针p1走n步,当两个指针再次相遇,相遇点即为环的入口。
环的长度的寻找方法为,先找到环中一点,然后一边往前一边计数,当再次走到此点时,即计数为环的长度。
环中一点寻找方法为快慢指针,同面试题15。若链表存在环,快慢指针一定相遇而且相遇与环中一点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
// 通过快慢指针判断链表中是否存在环,如果存在环,返回相遇节点,如果不存在环,返回NULL
ListNode* meetNode(ListNode* pHead)
{
if (pHead == NULL)
{
return pHead;
}
ListNode* slow = pHead;
ListNode* fast = slow->next;
if (fast == NULL)
{
return NULL;
}
while(slow != NULL && fast != NULL && fast->next != NULL)
{
if (slow == fast)
{
return fast;
}
slow = slow->next;
fast = fast->next->next;
}
return NULL;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
// 第一步:找到环中一个点
ListNode* meet = meetNode(pHead);
if (meet == NULL)
{
return NULL;
}
// 第二步:计算环的长度
int n = 1;
ListNode* tmp = meet->next;
while(tmp != meet)
{
tmp = tmp->next;
n++;
}
// 第三步:定义两个指针,指针p2先走n步
ListNode* p1 = pHead;
ListNode* p2 = pHead;
for(int i = 0;
i < n;
i++)
{
p2 = p2->next;
}
// p1,p2再次相遇之处,就是环的入口
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
};
思路2:如果可以用额外内存,其实把遍历过的节点存在vector里,第一个被再次遍历到的节点应该就是入口
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
vector list;
while(pHead != NULL)
{
if (find(list.begin(), list.end(), pHead) == list.end())
{
list.push_back(pHead);
pHead = pHead->next;
}
else {
break;
}
}
return pHead;
}
};
面试题57:删除链表中的重复节点解题思路:
在一个被排序的链表中,如何删除重复的节点。注意不是删除重复项,而是如果节点有重复节点,则将改节点和重复节点都删除
leetcode链接 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/
/** * Definition for singly-linked list. * struct ListNode { *int val; *ListNode *next; *ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if (head == NULL) { return NULL; } if (head->next == NULL) { return head; } ListNode* result = NULL; ListNode* pre = NULL; ListNode* cur = head; int begin = 1; while(cur != NULL) { bool needDelete = false; ListNode* next = cur->next; // cout << next->val << endl; // 只判断当前节点元素和下一个节点元素val是否相等,因为只有当节点值发生变化,才会走到这里,所以当前节点值和上一个节点一定不同 if (next != NULL && cur->val == next->val) { needDelete = true; // cout << "here" << endl; } if (!needDelete) { pre = cur; cur = cur->next; if (begin == 1) { result = pre; } begin = 0; }else { // 判断当前节点需要删除,找到所有跟当前节点值相同节点,全部删除 int value = https://www.it610.com/article/cur->val; ListNode* tmp = cur; while(tmp != NULL && tmp->val == value) { next = tmp->next; // delete tmp; // 不能delete头节点,会报错 // tmp = NULL; tmp = next; } if (pre == NULL) { ; } else{ // cout << pre->val << endl; pre->next = tmp; } cur = next; // cout << "here" << endl; } } return result; } };
注意!因为头节点可能被删除,因此当前删除函数应该是delete(ListNode** pHead)而不是delete(ListNode* pHead)。或者用返回值作为新的链表头。
因为链表是排序的,因此判断p->val和p->next->val即可,不需要存在vector中。
推荐阅读
- 由浅入深理解AOP
- 继续努力,自主学习家庭Day135(20181015)
- python学习之|python学习之 实现QQ自动发送消息
- 一起来学习C语言的字符串转换函数
- 定制一套英文学习方案
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- 《深度倾听》第5天──「RIA学习力」便签输出第16期
- 如何更好的去学习
- 【韩语学习】(韩语随堂笔记整理)
- 焦点学习田源分享第267天《来访》