2024年3月17日 算法学习
139. 单词拆分
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
注意,你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
和wordDict[i]
仅由小写英文字母组成wordDict
中的所有字符串 互不相同
思路
识别关键词,鉴定为完全背包。
完全背包基本公式:f[j] = min(f[j], f[j-vi]+wi)
状态表示:令f[j]
表示能否用前i个单词拼接出 s[:j]
状态转移:f[j] = f[j] || f[j-wordDict[i].size()]
,需要满足
j > wordDict[i].size()
s[:j-wordDict[i].size()] + wordDict[i] == s[:j]
代码
/*
* @lc app=leetcode.cn id=139 lang=cpp
*
* [139] 单词拆分
*/
#include<bits/stdc++.h>
using namespace std;
// @lc code=start
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> f(s.size(), 0); // f[j] 表示能否用前i个单词拼接出 s[:j]
f[0] = true;
for (int j = 0; j <= s.size(); j ++ ) {
for (int i = 0; i < wordDict.size(); i ++ ) {
if (s.substr(0, j-wordDict[i].size())+wordDict[i]==s.substr(0, j)) {
f[j] = f[j] || f[j-wordDict[i].size()];
}
}
}
return f[s.size()];
}
};
// @lc code=end
310. 最小高度树
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
给你一棵包含 n
个节点的树,标记为 0
到 n - 1
。给定数字 n
和一个有 n - 1
条无向边的 edges
列表(每一个边都是一对标签),其中 edges[i] = [ai, bi]
表示树中节点 ai
和 bi
之间存在一条无向边。
可选择树中任何一个节点作为根。当选择节点 x
作为根节点时,设结果树的高度为 h
。在所有可能的树中,具有最小高度的树(即,min(h)
)被称为 最小高度树 。
请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。
树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
示例 1:
输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。
示例 2:
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
输出:[3,4]
提示:
1 <= n <= 2 * 104
edges.length == n - 1
0 <= ai, bi < n
ai != bi
- 所有
(ai, bi)
互不相同 - 给定的输入 保证 是一棵树,并且 不会有重复的边
思路
用 BFS,一层一层从最外面向里面遍历
代码
/*
* @lc app=leetcode.cn id=310 lang=cpp
*
* [310] 最小高度树
*/
#include<bits/stdc++.h>
using namespace std;
// @lc code=start
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if (n == 1) return {0};
vector<vector<int>> g(n); // 邻接表存图
vector<int> degree(n, 0); // 存储每个节点的度
vector<int> ans;
queue<int> q; // 用于 BFS 的队列
for (auto edge: edges) {
g[edge[0]].push_back(edge[1]);
g[edge[1]].push_back(edge[0]);
degree[edge[0]]++;
degree[edge[1]]++;
}
for(int i = 0; i < n; i ++ )
if (degree[i] == 1)
q.push(i);
while(q.size()) {
ans.clear();
for (int i = q.size(); i ; i -- ) {
int x = q.front();
q.pop();
ans.push_back(x);
for (int ne: g[x])
if (--degree[ne] == 1)
q.push(ne);
}
}
return ans;
}
};
// @lc code=end
2024年3月17日 算法学习
139. 单词拆分
给你一个字符串 s
和一个字符串列表 wordDict
作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s
则返回 true
。
**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
注意,你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
和wordDict[i]
仅由小写英文字母组成wordDict
中的所有字符串 互不相同
思路
识别关键词,鉴定为完全背包。
完全背包基本公式:f[j] = min(f[j], f[j-vi]+wi)
状态表示:令f[j]
表示能否用前i个单词拼接出 s[:j]
状态转移:f[j] = f[j] || f[j-wordDict[i].size()]
,需要满足
j > wordDict[i].size()
s[:j-wordDict[i].size()] + wordDict[i] == s[:j]
代码
/*
* @lc app=leetcode.cn id=139 lang=cpp
*
* [139] 单词拆分
*/
#include<bits/stdc++.h>
using namespace std;
// @lc code=start
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> f(s.size(), 0); // f[j] 表示能否用前i个单词拼接出 s[:j]
f[0] = true;
for (int j = 0; j <= s.size(); j ++ ) {
for (int i = 0; i < wordDict.size(); i ++ ) {
if (s.substr(0, j-wordDict[i].size())+wordDict[i]==s.substr(0, j)) {
f[j] = f[j] || f[j-wordDict[i].size()];
}
}
}
return f[s.size()];
}
};
// @lc code=end
310. 最小高度树
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
给你一棵包含 n
个节点的树,标记为 0
到 n - 1
。给定数字 n
和一个有 n - 1
条无向边的 edges
列表(每一个边都是一对标签),其中 edges[i] = [ai, bi]
表示树中节点 ai
和 bi
之间存在一条无向边。
可选择树中任何一个节点作为根。当选择节点 x
作为根节点时,设结果树的高度为 h
。在所有可能的树中,具有最小高度的树(即,min(h)
)被称为 最小高度树 。
请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。
树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
示例 1:
输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。
示例 2:
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
输出:[3,4]
提示:
1 <= n <= 2 * 104
edges.length == n - 1
0 <= ai, bi < n
ai != bi
- 所有
(ai, bi)
互不相同 - 给定的输入 保证 是一棵树,并且 不会有重复的边
思路
用 BFS,一层一层从最外面向里面遍历
代码
/*
* @lc app=leetcode.cn id=310 lang=cpp
*
* [310] 最小高度树
*/
#include<bits/stdc++.h>
using namespace std;
// @lc code=start
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if (n == 1) return {0};
vector<vector<int>> g(n); // 邻接表存图
vector<int> degree(n, 0); // 存储每个节点的度
vector<int> ans;
queue<int> q; // 用于 BFS 的队列
for (auto edge: edges) {
g[edge[0]].push_back(edge[1]);
g[edge[1]].push_back(edge[0]);
degree[edge[0]]++;
degree[edge[1]]++;
}
for(int i = 0; i < n; i ++ )
if (degree[i] == 1)
q.push(i);
while(q.size()) {
ans.clear();
for (int i = q.size(); i ; i -- ) {
int x = q.front();
q.pop();
ans.push_back(x);
for (int ne: g[x])
if (--degree[ne] == 1)
q.push(ne);
}
}
return ans;
}
};
// @lc code=end