算法练习]leetcode"/>
[算法练习]leetcode
题目链接
力扣
字符串的 引力 定义为:字符串中 不同 字符的数量。
例如,"abbca" 的引力为 3 ,因为其中有 3 个不同字符 'a'、'b' 和 'c' 。
给你一个字符串 s ,返回 其所有子字符串的总引力 。
子字符串 定义为:字符串中的一个连续字符序列。
示例 1:
输入:s = "abbca"
输出:28
解释:"abbca" 的子字符串有:
- 长度为 1 的子字符串:"a"、"b"、"b"、"c"、"a" 的引力分别为 1、1、1、1、1,总和为 5 。
- 长度为 2 的子字符串:"ab"、"bb"、"bc"、"ca" 的引力分别为 2、1、2、2 ,总和为 7 。
- 长度为 3 的子字符串:"abb"、"bbc"、"bca" 的引力分别为 2、2、3 ,总和为 7 。
- 长度为 4 的子字符串:"abbc"、"bbca" 的引力分别为 3、3 ,总和为 6 。
- 长度为 5 的子字符串:"abbca" 的引力为 3 ,总和为 3 。
引力总和为 5 + 7 + 7 + 6 + 3 = 28 。
来源:力扣(LeetCode)
链接:
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
所有的连续子数组是[i, j] i <= j 的组合,直接枚举所有情况,是O(N^2)的时间复杂度,
可以考虑使用动态规划来分析,假设f(i)是以第i个元素为起始点的所有情况,
f(0) = [0, 0], [0,1], [0,2], [0,3] ……
f(1) = [1,1], [1,2], [1,3] ……
可以看到,f(1)的结果可以从f(0)推导出来,分为a[0] == a[1]和a[0] != a[1]的情况,
按照这个思路,可以这样写
class Solution {
public:long long appealSum(string s) {//init, get sum and each poslong long f = 0;map<int, vector<int>> pos;int len = s.size();for (int i = 0; i < len; i++) {int k = s[i];pos[k].push_back(i);f += pos.size();}long long ans = f;vector<int> dt(len);vector<long long> fs(len);dt[0] = 0;fs[0] = f;for (int i = 0; i < len-1; i++) {//f1 = f0 - dtint c = s[i];if (s[i] == s[i+1]) {fs[i+1] = fs[i] - 1;ans += fs[i+1];continue;}//find the pos of ivector<int>& arr = pos[c];int b = 0;int e = arr.size()-1;int p = e+1;while (b <= e) {int m = (b+e)/2;if (arr[m] > i) {e = m-1;p = m;} else {b = m+1;}}int d = len - i;if (p <= arr.size()-1) {d = arr[p] - i;}fs[i+1] = fs[i] - d;ans += fs[i+1];} return ans; }
};
对于这个题目,也可以假设f(i)是以a[i]为末尾的情况,这样处理,程序写起来更清楚一些,
上面的题目是求>=1的个数,下面的题目比较相似,是求==1的数量,采用f(i)是以a[i]为末尾的情况来处理,
力扣
class Solution {
public:int uniqueLetterString(string s) {const int n = s.size();int tt = 1000000000+7;//1.// dp[i]: 以s[i]结尾的子字符串的总引力// pre_idx[i]: 记录字符 'a'+i 之前出现的位置,如果之前没有出现,就 = -1long long dp[n];vector<vector<int>> pre_idx(26, vector<int>(2, -1));// int pre_idx[26][2] = {-1};//just the first one is -1// 2. initialdp[0] = 1;int c = s[0] - 'A';pre_idx[c][1] = 0;// 3. long long ans = 1;for (int i = 1; i < n; ++i) {c = s[i] - 'A'; char of pos i// int len = i - pre_idx[s[i] - 'A'] - 1;int dt = 0;//not appeared begforeif (pre_idx[c][1] == -1) {dt = i+1;} else {dt = (i-pre_idx[c][1])- (pre_idx[c][1]-pre_idx[c][0]); // (pre_idx[c][1]-pre_idx[c][0]) //new// - (i-pre_idx[c][0]);//old}dp[i] = dp[i - 1] + dt;pre_idx[c][0] = pre_idx[c][1];pre_idx[c][1] = i;//if (dp[i] > tt) {dp[i] = dp[i]%tt;}ans += dp[i];}// 4. return ans%tt;}
};
另外子数组的题目,需要考虑使用单调栈找左右区间,
力扣
更多推荐
[算法练习]leetcode
发布评论