LeetCode291周赛题解 '字符串总引力’详解直接跳到最后
LeetCode291周赛题解
class Solution {
public:
string removeDigit(string s, char d) {
int n = s.size();
string ans ="0";
for(int i = 0; i < n; i++)
{
string t = "";
if(s[i] == d)
{
t += s.substr(0, i - 0);
t += s.substr(i + 1, n - i);
}
ans = max(ans, t);
}
return ans;
}
};
class Solution {
public:
int minimumCardPickup(vector<int>& c) {
unordered_map<int,int> mp;
int n = c.size();
int ans = INT_MAX;
bool f = false;
for(int i = 0; i < n; i++)
{
if(mp.find(c[i]) == mp.end())
{
mp[c[i]] = i;
}
else
{
ans = min(ans, i - mp[c[i]] + 1);
mp[c[i]] = i;
f = true;
}
}
if(!f)
return -1;
return ans;
}
};
class Solution {
public:
int countDistinct(vector<int>& nums, int k, int p) {
int n = nums.size();
set<string> s;
for(int i = 0; i < n; i++)
{
string str = "";
int t = 0;
for(int j = i; j < n; j++)
{
str += to_string(nums[j]);
str += ',';
if(nums[j] % p == 0)
t++;
if(t > k)
break;
s.insert(str);
}
}
return s.size();
}
};
第四题:字符串总引力 -详解
提示 1-1
将所有子串按照其末尾字符的下标分组。
提示 1-2
考虑两组相邻的子串:以
s
[
i
−
1
]
s[i−1]
s[i−1]结尾的子串、以
s
[
i
]
s[i]
s[i]结尾的子串。
提示 1-3
以
s
[
i
]
s[i]
s[i] 结尾的子串,可以看成是以
s
[
i
−
1
]
s[i−1]
s[i−1] 结尾的子串,在末尾添加上 s[i]组成。
上面这一串提示是思考子串统计类问题的通用技巧之一。
提示 2-1
从左往右遍历
s
s
s,考虑将
s
[
i
]
s[i]
s[i] 添加到以
s
[
i
−
1
]
s[i−1]
s[i−1] 结尾的子串的末尾。添加后,这些子串的引力值会增加多少?
提示 2-2
分类讨论:
-
如果 s [ i ] s[i] s[i] 之前没有遇到过,那么这些子串的引力值都会增加 1 1 1,这些子串的引力值之和会增加 i i i,再加上 1 1 1,即 s [ i ] s[i] s[i] 单独组成的子串的引力值;
-
如果 s [ i ] s[i] s[i] 之前遇到过,设其上次出现的下标为 j j j,那么向子串 s [ 0.. i − 1 ] , s [ 1.. i − 1 ] , s [ 2.. i − 1 ] , ⋯ , s [ j . . i − 1 ] s[0..i−1], s[1..i−1], s[2..i−1],⋯,s[j..i−1] s[0..i−1],s[1..i−1],s[2..i−1],⋯,s[j..i−1]的末尾添加 s [ i ] s[i] s[i] 后,这些子串的引力值是不会变化的,因为 s [ i ] s[i] s[i] 已经在 s [ j ] s[j] s[j] 处出现过了;而子 s [ j + 1.. i − 1 ] , s [ j + 2.. i − 1 ] , ⋯ , s [ i − 1.. i − 1 ] s[j+1..i−1], s[j+2..i−1],⋯,s[i−1..i−1] s[j+1..i−1],s[j+2..i−1],⋯,s[i−1..i−1] 由于不包含字符 s [ i ] s[i] s[i],这些子串的引力值都会增加 1 1 1,因此有 i − j − 1 i−j−1 i−j−1 个子串的引力值会增加 1 1 1,这些子串的引力值之和会增加 i − j − 1 i−j−1 i−j−1,再加上 1 1 1,即 s [ i ] s[i] s[i] 单独组成的子串的引力值。
模拟上述过程,遍历 s s s 的过程中用一个变量 s u m G sumG sumG 维护以 s [ i ] s[i] s[i] 结尾的子串的引力值之和,同时用一个数组 p o s pos pos 记录每个字符最近一次出现的下标。
累加遍历中的 s u m G sumG sumG 即为答案。
这里附上我的理解图(讨论样例一,包含特殊情况,abbca):
至此,所有的情况均分析完,最后的结果,我们可以一直累加当前斜对角层的引力数,当前斜对角层的引力数又等于上一层的加上当前层字符贡献的。代码如下:
class Solution {
public:
long long appealSum(string &s) {
long ans = 0L, sum_g = 0L;
vector<int> pos(26, -1);// -1初始化,刚好处理了,字符没出现过 i + 1
for (int i = 0; i < s.length(); ++i) {
char c = s[i] - 'a';
sum_g += i - pos[c]; //上一斜对角层 + 这一层字符贡献
ans += sum_g; //总的 累加 这一斜对角层
pos[c] = i;//维护字符位置
}
return ans;
}
};