s0131
ci/woodpecker/push/test Pipeline was successful Details

This commit is contained in:
Sainnhe Park 2023-02-02 17:34:34 +08:00
parent a145bbc05f
commit 19212e880b
5 changed files with 97 additions and 4 deletions

View File

@ -0,0 +1,14 @@
#ifndef S0131_PALINDROME_PARTITIONING_HPP
#define S0131_PALINDROME_PARTITIONING_HPP
#include <string>
#include <vector>
using namespace std;
class S0131 {
public:
vector<vector<string>> partition(string s);
};
#endif

View File

@ -42,6 +42,7 @@
- [总结](./backtrack.md)
- [组合问题](./combinations.md)
- [切割问题](./split.md)
# STL

View File

@ -9,10 +9,43 @@
关键就是要学会分析和画图,然后确定传入参数。只要传入参数确定了代码框架就确定了 (返回值一般是 `void`)
- 得有一个 `&result` 来存放结果
- 每一层的节点所包含的数据是什么,需要一系列的参数来描述当前节点的状态(传入的参数实际上是上一轮迭代的数据)。
- 终止条件是什么?回溯法中的每个节点并不是真的树状节点,没有 `nullptr` ,因此用空指针来判断是否到了叶子结点并不合理,需要其它的一些方法来确定是否到达叶子节点,比如高度。
- 每次迭代要在上一次迭代的基础上进行哪些操作?需要哪些参数才能完成这些操作?
- 思考这棵树怎么画,每层遍历的逻辑是什么,每条边的操作逻辑是什么。
- 得设计一个数据结构 `NodeState` 来存放当前节点状态。该数据结构的可扩展性必须要强,需要满足以下条件:
- 能描述当前节点的状态
- 能作为最终结果存储
- 能根据当前节点更新状态和撤销之前的更改
- 得有一个 `&result` 来存放结果,这个 `&result` 通常是一个向量 `vector<NodeState> &`,里面存放了节点状态。
- 其它传入参数用来完成每层遍历操作和每条边的操作。
设计完了数据结构之后来看看具体代码怎么写。模板如下:
```cpp
void backtrack(NodeState &node, vector<NodeState> &result, int para1, int para2, int para3) {
// 终止条件
// 回溯法中的每个节点并不是真的树状节点,没有 `nullptr` ,因此用空指针来判断是否到了叶子结点并不合理,需要其它的一些方法来确定是否到达叶子节点,比如高度。
if (/* end condition */) {
result.push_back(node);
return;
}
// 遍历该节点的所有子节点,即遍历下一层
for (...) {
// 剪枝
// 当现在的节点不可能出现我们想要的结果时,直接跳过。
if (/* out of scope */) {
continue;
}
// 处理节点
// 现在 node 中的数据描述的是当前节点,
// handle(node) 一般是让 node 中的数据变成子节点的数据
handle(node);
// 递归
backtrack(node, result, para1, para2, para3);
// 撤销数据处理,让 node 中的数据再次变回描述当前节点的数据
revert(node);
}
}
```
复杂度分析:

5
notes/src/split.md Normal file
View File

@ -0,0 +1,5 @@
# 切割问题
## [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/)
![](https://paste.sainnhe.dev/FHTE.jpg)

View File

@ -0,0 +1,40 @@
#include "s0131_palindrome_partitioning.hpp"
bool isPalindrome(const string &s, int begin, int end) {
for (int i = begin, j = end; i <= j; ++i, --j) {
if (s[i] != s[j]) return false;
}
return true;
}
/**
* @brief
*
* @param path
* @param result
* @param s
* @param startIndex s[0...startIndex - 1] path
*/
void partitionDFS(vector<string> &path, vector<vector<string>> &result, const string &s, int startIndex) {
int len = s.length();
// 终止条件
if (startIndex == len) {
result.push_back(path);
}
for (int i = startIndex; i < len; ++i) {
// 如果 s[startIndex...i] 是回文串,则进入下一层
if (isPalindrome(s, startIndex, i)) {
path.push_back(s.substr(startIndex, i - startIndex + 1));
partitionDFS(path, result, s, i + 1);
path.pop_back();
}
}
}
vector<vector<string>> S0131::partition(string s) {
vector<vector<string>> result{};
vector<string> path{};
partitionDFS(path, result, s, 0);
return result;
}