【七十一】【算法分析与设计】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

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

poj2406(连续重复子串)

题意:判断串s是不是str^n,求str的最大长度。 解题思路:kmp可解,后缀数组的倍增算法超时。next[i]表示在第i位匹配失败后,自动跳转到next[i],所以1到next[n]这个串 等于 n-next[n]+1到n这个串。 代码如下; #include<iostream>#include<algorithm>#include<stdio.h>#include<math.

poj3261(可重复k次的最长子串)

题意:可重复k次的最长子串 解题思路:求所有区间[x,x+k-1]中的最小值的最大值。求sa时间复杂度Nlog(N),求最值时间复杂度N*N,但实际复杂度很低。题目数据也比较水,不然估计过不了。 代码入下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring