当前位置: 首页 > news >正文

【动态规划:子数组/子串系列】单词拆分 环绕字符串中唯⼀的子字符串

在这里插入图片描述

单词拆分(medium)

139. 单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s

注意: 不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 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 中的所有字符串 互不相同

解题思路

​ 状态表示和状态转移方程的解析如下图所示:

在这里插入图片描述

在这里插入图片描述

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {// 优化:把字典放到hash中unordered_set<string> hash;for(const auto &e : wordDict)hash.insert(e);// 创建dp表,dp[i]表示从[0,i]区间内是否可以拼成一个字符串int n = s.size();vector<bool> dp(n + 1); // 多开一个虚拟位置,防止越界dp[0] = true; // 给虚拟位置初始化,保证后面填表正确s = ' ' + s;  // 使原始字符串的下标统⼀+1,让我们无需在后面访问s的时候去控制下标// 填表for(int i = 1; i <= n; ++i){for(int j = i; j >= 1; --j){if(dp[j - 1] == true && hash.count(s.substr(j, i - j + 1))){dp[i] = true;break; // 只要找到了就break}}}return dp[n];}
};

在这里插入图片描述

8、环绕字符串中唯⼀的子字符串(medium)

467. 环绕字符串中唯一的子字符串

定义字符串 base 为一个 "abcdefghijklmnopqrstuvwxyz" 无限环绕的字符串,所以 base 看起来是这样的:

  • "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....".

给你一个字符串 s ,请你统计并返回 s 中有多少 不同非空子串 也在 base 中出现。

示例 1:

输入:s = "a"
输出:1
解释:字符串 s 的子字符串 "a" 在 base 中出现。

示例 2:

输入:s = "cac"
输出:2
解释:字符串 s 有两个子字符串 ("a", "c") 在 base 中出现。

示例 3:

输入:s = "zab"
输出:6
解释:字符串 s 有六个子字符串 ("z", "a", "b", "za", "ab", and "zab") 在 base 中出现。

提示:

  • 1 <= s.length <= 105
  • s 由小写英文字母组成

解题思路

​ 这道题首先要先看懂题,其实就是要求这个字符串 base 的数量,而 base 其实就是 acbd…… 连续的子串,不能是 acd 这种只能是连续的 abcd,一定要先弄懂题目要求,弄懂了才能做!依旧是按照我们分析的几步来:

  • 状态表示
    • 还是一样,动态规划这类题还是按照 “经验+题目要求”,比如 以某处为结尾然后……的情况,这道题也是如此。
    • 所以我们可以设定 dp[i] 表示以 i 结尾的所有子串中,是 base 子串的数量
  • 状态转移方程
    • 既然是要求以 i 结尾的所有子串的可能,那么我们按长度来解析:
      • 子串长度为1:也就是当前字符本身,那么肯定是算一种 base 字符串的,所以 此时 dp 值为 1
      • 子串长度大于1:这个时候就要根据之前的状态来得到当前的状态了!
        • 因为此时子串长度大于 1,那么肯定会有 i-1 位置字符的参与,那么其实就转化为了 dp[i - 1] 的值了,因为它表示以 i-1 字符结尾的所有字符串中 base 字符串的出现次数。
        • 如果此时当前字符能和以 i-1 结尾的所有 base 字符串拼接起来,那么得到的出现此时就是 dp[i - 1],那么如何才能将 i 处字符和之前的字符串符合拼接起来呢❓❓❓
          • 其实就是题目要求,要连续的 abcd…… 这种形式,所以我们只需要判断是否 s[i] - 1 == s[i - 1] 即可,但是要注意的是有可能 s[i]‘a’,题目说到这是一个环绕 base 字符串,也就是说首尾相连,那么要让它们拼接起来,还得满足 s[i] == ‘a’ && s[i - 1] == ‘z’,把这种情况考虑到了才是完整的情况!
        • 也就是说,当 s[i] - 1 == s[i - 1] 或者 s[i] == ‘a’ && s[i - 1] == ‘z’ 有一个满足的时候,d[i] 才等于 dp[i - 1]
    • 所以状态转移方程:dp[i] = 1 + dp[i - 1],其中 dp[i - 1] 是需要满足条件才能加上的,而 1 是必加项。
  • 初始化
    • 因为状态转移方程涉及到 i-1,所以我们要对 dp[0] 进行初始化,如果只有两个字符,比如 “ab”,此时 dp[i - 1] 是成立的,需要加上,那么 dp[i] = 1 + dp[i - 1] 就得等于 2 才对,所以 dp[0] 初始化为 1
    • 但其实还有更妙的做法,因为我们上面不是得到了 dp[i] 的推导中,肯定要加上一吗,那么我们只要将整个 dp 数组初始化为 1,往后在求 dp[i] 的时候我们 直接使用 +=,比如 dp[i] += dp[i - 1] 的时候,其中 dp[i] 本身已经初始化为了 1,就不用再去加上 1 了,当然不这么做也是可以的!
  • 填表顺序
    • 显而易见,填表顺序「从左往右」
  • 返回值
    • 返回值并不是简单的累加上 dp 表的所有值,因为有可能字符串 s 中有重复的字符!
      • 比如说【abczab】此时对于第一个字符 ‘b’ 来说,它有出现过子串 ‘b’、“ab”,所以 dp 值为 2;而对于第二个字符 ‘b’ 来说,它出现过 ‘b’、“ab” 和 “zab”,dp 值就为 3,它其中就包括了第一个字符 ‘b’ 所出现的子串,那么就重复了,此时要是我们去累加整个 dp 表的值,那么就多加了 2,那就错了!
    • 可以发现,我们只需要取出现相同字符中,dp 值大的那个,它出现的子串肯定也包括了其它相同字符出现的子串!所以我们 去重的方法就是取这些相同字符中 dp 值大的那个!
    • 所以我们可以使用哈希表,对于此题直接使用一个 26 空间大小的数组即可,因为只出现小写字母!然后将每个字符映射到对应的位置上去,并且 hash[i] 更新的是这个相同字符的最大 dp 值!
    • 最后我们再去这个哈希表中累加出现的这些最大 dp 值,返回最终累加结果即可!
class Solution {
public:int findSubstringInWraproundString(string s) {// 创建dp表,dp[i]表示以i结尾的所有子串中的base的数量int n = s.size();vector<int> dp(n, 1); // 都初始化为1// 填表for(int i = 1; i < n; ++i){// 注意判断这里是s[i]-1而不是s[i]+1,不要搞错了!if((s[i] - 1 == s[i - 1]) || (s[i - 1] == 'z' && s[i] == 'a'))dp[i] += dp[i - 1];}// 返回base出现的总和之前的处理:// 注意在字符串s中可能有重复的字符,这样子的话两个相同字符的dp值可能是不一样的// 我们只取大的那个,因为dp值大的那个包含了dp值小的那个// 所以我们要做映射,将出现的字符的最大dp值映射到hash数组中int hash[26] = {0};for(int i = 0; i < n; ++i)hash[s[i] - 'a'] = max(hash[s[i] - 'a'], dp[i]);// 累加结果并且返回int ret = 0;for(int i = 0; i < 26; ++i)ret += hash[i];return ret;}
};

在这里插入图片描述

http://www.dtcms.com/a/428825.html

相关文章:

  • 做网站服务器要什么系统推广怎么推广
  • qq网站登录北京网站优化推广分析
  • CNN的可视化:特征图与卷积核可视化方法(代码实现)
  • 读写RPLMN等APDU log显示为FF FF FF……问题研究
  • CKAD-CN 考试知识点分享(8) 升级与回滚
  • 网站建设公司该如何选择服务称赞的项目管理平台
  • 哪里做网站比较快wordpress主题 视频
  • 网站建设实训总结范文品牌市场营销策略
  • 网站界面设计软件网站备案去哪注销
  • 网页设计感十足的网站移动开发软件
  • LangChain 中 “附加 OpenAI 函数” 和 “附加 OpenAI 工具”
  • 山东住房和城乡建设厅网站登陆平面设计必学软件
  • 凡客建站官网登录入口Wordpress仿制网站
  • 网站开发技术的发展开发者门户网站是什么意思
  • GIS 相关基础知识
  • 陕西有色建设有限公司官方网站花生壳动态域名做网站
  • 企业网站seo平台不孕不育网站建设总结
  • 做短连接的网站织梦门户网站
  • 怎么做网站流量统计wordpress值得买模板
  • 【DRAM存储器五十八】LPDDR5介绍--IO结构,VREF和ODT有什么关系?
  • 增塑剂网站建设wordpress google
  • 什么是网站的主页seo优化排名工具
  • 网站域名怎么购买大连在哪个城市
  • 新电脑(包含联想电脑)访问正常的系统加载不出页面,但是网络telnet又是通畅的(PG数据库连接public模式下能看到表及数据,其他模式下的表和数据看不了)
  • 中为网站建设重庆cms建站模板
  • 宝安中心医院是三甲医院吗seo工具共享网站
  • useref原理
  • 德惠市建设局网站WordPress面包屑主题
  • flask做的网站 网址青浦专业网站建设
  • 开闭原则详解(OCP)