【七十一】【算法分析与设计】467. 环绕字符串中唯一的子字符串,940. 不同的子序列 II,子串的划分,子序列的划分,区间划分---递推

本文主要是介绍【七十一】【算法分析与设计】467. 环绕字符串中唯一的子字符串,940. 不同的子序列 II,子串的划分,子序列的划分,区间划分---递推,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 <= 10(5)

  • s 由小写英文字母组成

1.

子串的划分,以某个位置结尾的子串,进行子串的划分.

把所有位置结尾的子串中出现在base个数记录下来即可.

2.

只需要记录以某位置结尾往前最长的连续子串长度即可.

例如abcde,bcde,cde,de,e,最长的连续子串长度是5,依次对应五个数量.

3.

子串的划分----分治

 
#include <bits/stdc++.h>  // 引入常用的头文件
using namespace std;class Solution {
public:using ll = long long;  // 定义类型别名ll,表示长整型long longstring s;              // 定义字符串s,存储输入字符串vector<ll> dp;         // 使用动态规划存储中间结果,dp[i]存储以s[i]结尾的子串的合法子串数量vector<ll> count;      // 记录每个字母为结束字符的最长子串长度// 初始化函数,清空并重设dp和count数组void solveinit() {dp.clear();                     // 清空dp数组dp.resize(s.size(), -1);        // 重设dp数组大小,初始值为-1count.clear();                  // 清空count数组count.resize(26);               // 重设count数组大小,大小为26(26个字母)}// 深度优先搜索函数,用于计算以第i个字符结束的子串的合法子串数量ll dfs(ll i) {if (dp[i] != -1)                // 如果dp[i]已计算过,直接返回结果return dp[i];if (i - 1 >= 0) {               // 如果不是第一个字符,可以考虑前一个字符if (s[i] != 'a') {          // 当前字符不是'a'时if (s[i - 1] == s[i] - 1) {  // 如果前一个字符正好是当前字符的前一个字母dp[i] = dfs(i - 1) + 1;  // 递归计算前一个字符,并加上当前字符形成的新的子串} else {dp[i] = 1;          // 否则,当前字符自成一组}} else {if (s[i - 1] == 'z') {  // 当前字符是'a'且前一个字符是'z'dp[i] = dfs(i - 1) + 1;  // 递归计算前一个字符,并加上当前字符形成的新的子串} else {dp[i] = 1;          // 否则,当前字符自成一组}}} else {dp[i] = 1;                  // 如果是第一个字符,只有当前字符自身一个子串}return dp[i];                   // 返回以s[i]结尾的合法子串数量}// 主函数,计算字符串s中有多少不同非空子串也在环绕字符串base中出现int findSubstringInWraproundString(string _s) {s = _s;                         // 存储输入字符串solveinit();                    // 初始化dp和count数组for (ll i = 0; i < s.size(); i++) {dfs(i);                     // 对每个字符调用dfs函数,计算以每个字符结尾的子串数量}ll ans = 0;vector<bool> visited(26);       // 标记数组,记录每个字符是否被访问过for (ll i = 0; i < s.size(); i++) {int index = s[i] - 'a';     // 当前字符对应的索引count[index] = max(count[index], dp[i]);  // 更新以当前字符结尾的最大子串数量}for (ll i = 0; i < 26; i++) {ans += count[i];            // 累加每个字母对应的最长子串数量}return ans;                     // 返回结果}
};

940. 不同的子序列 II

给定一个字符串 s,计算 s不同非空子序列 的个数。因为结果可能很大,所以返回答案需要对 10^9 + 7 取余

字符串的 子序列 是经由原字符串删除一些(也可能不删除)字符但不改变剩余字符相对位置的一个新字符串。

  • 例如,"ace""abcde" 的一个子序列,但 "aec" 不是。

示例 1:

输入:s = "abc" 输出:7 解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。

示例 2:

输入:s = "aba" 输出:6 解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。

示例 3:

输入:s = "aaa" 输出:3 解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。

提示:

  • 1 <= s.length <= 2000

  • s 仅由小写英文字母组成

1.

假设s长度为n.

区间[0,n-1]的字符串的不同的子序列个数是多少.

区间[0,n-2]的字符串的不同的子序列个数是多少.

可以选择由[0,n-2]区间字符串的不同子序列个数多少推导出[0,n-1]的字符串的不同的子序列个数是多少.

因为新增的子序列是[0,n-2]区间所有子序列后面全部加上n-1位置的字符所组成的子序列加上n-1位置单独的字符子序列.

只需要完成新增子序列与老子序列的去重操作即可.

新增子序列都是以n-1位置结尾的子序列,一定是包含了所有的以n-1字符结尾的可能性.

所以老子序列中去掉以n-1字符结尾的可能性加上其他字符结尾的个数即可.

2.

子序列的划分----分治

长度的划分,递推,增加的子序列很好计算.

 
class Solution {
public:using ll = long long; // 定义类型别名 ll,表示长整型 long longstring s; // 用于存储输入的字符串vector<ll> count; // 使用一个数组来统计每个字符作为子序列结尾的不同子序列个数const ll MOD = 1e9 + 7; // 定义常量 MOD,取值为 10^9 + 7,用于结果的模运算void solveinit() {count.clear(); // 清空 count 数组count.resize(26); // 将 count 数组大小重新设置为26(对应26个英文字母)}int distinctSubseqII(string _s) {s = _s; // 将传入的字符串赋值给成员变量 ssolveinit(); // 调用初始化函数,准备 count 数组for (ll i = 0; i < s.size(); i++) { // 遍历字符串 s 的每个字符ll all = 0; // 初始化 all 变量,用来统计到当前字符为止的所有可能子序列的数量for (ll j = 0; j < count.size(); j++) { // 遍历 count 数组,累加之前所有字符的子序列总数all = (all + count[j]) % MOD; // 将累加结果进行模运算,防止溢出}ll index = s[i] - 'a'; // 计算当前字符在 count 数组中的索引位置count[index] = (all + 1) % MOD; // 更新当前字符的子序列数。加1是因为当前字符本身也是一个子序列}ll ans = 0; // 初始化答案变量,用来存储最终的不同子序列总数for (ll i = 0; i < count.size(); i++) { // 遍历 count 数组,将所有字符的子序列数累加ans = (ans + count[i]) % MOD; // 累加的同时进行模运算,防止溢出}return ans; // 返回最终计算的结果}
};

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

这篇关于【七十一】【算法分析与设计】467. 环绕字符串中唯一的子字符串,940. 不同的子序列 II,子串的划分,子序列的划分,区间划分---递推的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/943715

相关文章

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

Golang中拼接字符串的6种方式性能对比

《Golang中拼接字符串的6种方式性能对比》golang的string类型是不可修改的,对于拼接字符串来说,本质上还是创建一个新的对象将数据放进去,主要有6种拼接方式,下面小编就来为大家详细讲讲吧... 目录拼接方式介绍性能对比测试代码测试结果源码分析golang的string类型是不可修改的,对于拼接字

MyBatis-Plus中静态工具Db的多种用法及实例分析

《MyBatis-Plus中静态工具Db的多种用法及实例分析》本文将详细讲解MyBatis-Plus中静态工具Db的各种用法,并结合具体案例进行演示和说明,具有很好的参考价值,希望对大家有所帮助,如有... 目录MyBATis-Plus中静态工具Db的多种用法及实例案例背景使用静态工具Db进行数据库操作插入

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock

Java对象和JSON字符串之间的转换方法(全网最清晰)

《Java对象和JSON字符串之间的转换方法(全网最清晰)》:本文主要介绍如何在Java中使用Jackson库将对象转换为JSON字符串,并提供了一个简单的工具类示例,该工具类支持基本的转换功能,... 目录前言1. 引入 Jackson 依赖2. 创建 jsON 工具类3. 使用示例转换 Java 对象为

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1