s0142
This commit is contained in:
parent
4099f80edb
commit
acc4f2169d
24
include/s0142_linked_list_cycle.hpp
Normal file
24
include/s0142_linked_list_cycle.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef S0142_LINKED_LIST_CYCLE_HPP
|
||||||
|
#define S0142_LINKED_LIST_CYCLE_HPP
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
struct ListNode {
|
||||||
|
int val;
|
||||||
|
ListNode* next;
|
||||||
|
ListNode(int x) : val(x), next(nullptr) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IterResult {
|
||||||
|
ListNode *node;
|
||||||
|
bool meet;
|
||||||
|
};
|
||||||
|
|
||||||
|
class S0142 {
|
||||||
|
public:
|
||||||
|
std::unordered_map<ListNode *, int> footprint;
|
||||||
|
IterResult iter(ListNode *fast, ListNode* slow, bool startUp);
|
||||||
|
ListNode *detectCycle(ListNode *head);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -10,6 +10,7 @@
|
|||||||
# 链表
|
# 链表
|
||||||
|
|
||||||
- [总结](./linked-list.md)
|
- [总结](./linked-list.md)
|
||||||
|
- [环形链表](./linked_list_cycle.md)
|
||||||
|
|
||||||
# 字符串
|
# 字符串
|
||||||
|
|
||||||
|
@ -8,14 +8,18 @@
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
void iter(ListNode *node) {
|
void iter(ListNode *node) {
|
||||||
|
// 终止条件
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
your
|
从前往后遍历
|
||||||
condition
|
|
||||||
*/
|
*/
|
||||||
iter(node->next);
|
iter(node->next);
|
||||||
|
/*
|
||||||
|
从后往前遍历
|
||||||
|
*/
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
40
notes/src/linked_list_cycle.md
Normal file
40
notes/src/linked_list_cycle.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# 环形链表
|
||||||
|
|
||||||
|
[Leetcode](https://leetcode.com/problems/linked-list-cycle-ii/)
|
||||||
|
|
||||||
|
可以用回溯法解这道题。
|
||||||
|
|
||||||
|
首先递归遍历链表的一般结构如下:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void iter(ListNode *node) {
|
||||||
|
// 终止条件
|
||||||
|
if (node == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
从前往后遍历
|
||||||
|
*/
|
||||||
|
iter(node->next);
|
||||||
|
/*
|
||||||
|
从后往前遍历
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
而查找链表中是否有环的思路是快慢指针,如果相遇则说明有环。
|
||||||
|
|
||||||
|
所以我们可以这样:
|
||||||
|
|
||||||
|
终止条件是快指针走到链表末尾或者快慢指针相遇。
|
||||||
|
|
||||||
|
从前往后遍历不需要做什么额外操作。
|
||||||
|
|
||||||
|
从后往前遍历的时候先把快指针的足迹记录到一个哈希表中,键值是节点地址,值是快指针经过的次数。
|
||||||
|
|
||||||
|
当出现以下两种情况的时候就说明找到了环的入口:
|
||||||
|
|
||||||
|
1. footprint[fast] == 1 && footprint[fast->next] > 1
|
||||||
|
2. footprint[fast->next] == 1 && footprint[fast->next->next] > 1
|
||||||
|
|
70
src/s0142_linked_list_cycle.cpp
Normal file
70
src/s0142_linked_list_cycle.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "s0142_linked_list_cycle.hpp"
|
||||||
|
|
||||||
|
IterResult S0142::iter(ListNode *fast, ListNode *slow, bool startUp) {
|
||||||
|
// 终止条件
|
||||||
|
if (fast == nullptr || slow == nullptr) {
|
||||||
|
return {nullptr, false};
|
||||||
|
}
|
||||||
|
if (fast->next == nullptr) {
|
||||||
|
return {nullptr, false};
|
||||||
|
}
|
||||||
|
if (slow->next == slow) {
|
||||||
|
return {slow, true};
|
||||||
|
}
|
||||||
|
// 当两指针相遇时同样达到终止条件
|
||||||
|
if (fast == slow && !startUp) {
|
||||||
|
return {nullptr, true};
|
||||||
|
}
|
||||||
|
// 递归
|
||||||
|
IterResult result = iter(fast->next->next, slow->next, false);
|
||||||
|
// 从后往前遍历
|
||||||
|
// 达到了终止条件,但是没有两个指针遇见过
|
||||||
|
// 这说明没有环
|
||||||
|
if (!result.meet) {
|
||||||
|
return {nullptr, false};
|
||||||
|
} else {
|
||||||
|
// 有环的情况
|
||||||
|
// 我们把 fast 和 fast-next 节点所经过的足迹全部记录下来
|
||||||
|
// key 是所经过的节点
|
||||||
|
// value 是所经过的次数
|
||||||
|
if (footprint.count(fast) == 0) {
|
||||||
|
footprint[fast] = 1;
|
||||||
|
} else {
|
||||||
|
footprint[fast] += 1;
|
||||||
|
}
|
||||||
|
if (footprint.count(fast->next) == 0) {
|
||||||
|
footprint[fast->next] = 1;
|
||||||
|
} else {
|
||||||
|
footprint[fast->next] += 1;
|
||||||
|
}
|
||||||
|
// 什么情况下是环的入口呢?
|
||||||
|
// 1. footprint[fast] == 1 && footprint[fast->next] > 1
|
||||||
|
// 2. footprint[fast->next] == 1 && footprint[fast->next->next] > 1
|
||||||
|
if (footprint.count(fast) == 1 && footprint.count(fast->next) == 1) {
|
||||||
|
if (footprint[fast] == 1 && footprint[fast->next] > 1) {
|
||||||
|
return {fast->next, true};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (footprint.count(fast->next) == 1 &&
|
||||||
|
footprint.count(fast->next->next) == 1) {
|
||||||
|
if (footprint[fast->next] == 1 && footprint[fast->next->next] > 1) {
|
||||||
|
return {fast->next->next, true};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 返回
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListNode *S0142::detectCycle(ListNode *head) {
|
||||||
|
if (head == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (head->next == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// 递归函数无法处理所有节点都在环里的情况,所以在这里加一个哑节点
|
||||||
|
ListNode dummy = ListNode(0);
|
||||||
|
dummy.next = head;
|
||||||
|
return iter(&dummy, &dummy, true).node;
|
||||||
|
}
|
57
tests/s0142_linked_list_cycle.cpp
Normal file
57
tests/s0142_linked_list_cycle.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "s0142_linked_list_cycle.hpp"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
TEST(Problem142, Case1) {
|
||||||
|
ListNode node1 = ListNode(3);
|
||||||
|
ListNode node2 = ListNode(2);
|
||||||
|
ListNode node3 = ListNode(0);
|
||||||
|
ListNode node4 = ListNode(-4);
|
||||||
|
node1.next = &node2;
|
||||||
|
node2.next = &node3;
|
||||||
|
node3.next = &node4;
|
||||||
|
node4.next = &node2;
|
||||||
|
S0142 solution;
|
||||||
|
EXPECT_EQ(solution.detectCycle(&node1), &node2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Problem142, Case2) {
|
||||||
|
ListNode node1 = ListNode(3);
|
||||||
|
ListNode node2 = ListNode(2);
|
||||||
|
ListNode node3 = ListNode(0);
|
||||||
|
ListNode node4 = ListNode(-4);
|
||||||
|
node1.next = &node2;
|
||||||
|
node2.next = &node3;
|
||||||
|
node3.next = &node4;
|
||||||
|
node4.next = &node1;
|
||||||
|
S0142 solution;
|
||||||
|
EXPECT_EQ(solution.detectCycle(&node1), &node1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Problem142, Case3) {
|
||||||
|
ListNode node1 = ListNode(3);
|
||||||
|
ListNode node2 = ListNode(2);
|
||||||
|
ListNode node3 = ListNode(0);
|
||||||
|
ListNode node4 = ListNode(-4);
|
||||||
|
node1.next = &node2;
|
||||||
|
node2.next = &node3;
|
||||||
|
node3.next = &node4;
|
||||||
|
S0142 solution;
|
||||||
|
EXPECT_EQ(solution.detectCycle(&node1), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Problem142, Case4) {
|
||||||
|
ListNode node1 = ListNode(1);
|
||||||
|
ListNode node2 = ListNode(2);
|
||||||
|
node1.next = &node2;
|
||||||
|
node2.next = &node1;
|
||||||
|
S0142 solution;
|
||||||
|
EXPECT_EQ(solution.detectCycle(&node1), &node1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Problem142, Case5) {
|
||||||
|
ListNode node1 = ListNode(1);
|
||||||
|
node1.next = &node1;
|
||||||
|
S0142 solution;
|
||||||
|
EXPECT_EQ(solution.detectCycle(&node1), &node1);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user