2024年3月17日 算法学习

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
  • swordDict[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 个节点的树,标记为 0n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 aibi 之间存在一条无向边。

可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h 。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树

请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。

树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。

示例 1:

img

输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。

示例 2:

img

输入: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
  • swordDict[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 个节点的树,标记为 0n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 aibi 之间存在一条无向边。

可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h 。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树

请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。

树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。

示例 1:

img

输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。

示例 2:

img

输入: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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值