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_cycle.md)
|
||||
|
||||
# 字符串
|
||||
|
||||
|
@ -8,14 +8,18 @@
|
||||
|
||||
```cpp
|
||||
void iter(ListNode *node) {
|
||||
// 终止条件
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
your
|
||||
condition
|
||||
从前往后遍历
|
||||
*/
|
||||
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