3.19
思维、dp、字符串
子串分值和
thinking
朴素的做法是进行双层循环,考虑考虑到数据量为1e6,显然会超时。
我们具体分析题意:我们需要求解的是对于每一个子串,我们需要知道在这个子串中,26个字母是否出现。对于长度为n的字符串,一共有\(\frac{n*(n+1)}{2}\)个子串。
我们从一个例子来看解法:
a(……)a(…….)a(……….)
对于上述这么一个子串,我们考虑a出现在不同的子串的个数,答案加上这个数,循环26次即可。显然,我们要求a出现的子串个数是比较复杂的,我们进行反过来进行思考,我们求取a没有出现的字串数,再用总的子串数减去即可。已知a将字符串分成了k段,我们只需要统计k段的字串个数即可,剩下的子串,一定是包含a的,如此,我们解决了这题
solution
using ll=long long;
void solve() {
vector<vector<int>> a(26);
string s;cin>>s;
ll n=s.size();
for(int i=0;i<n;++i) {
a[s[i]-'a'].push_back(i);
}
ll ans=0;
for(int i=0;i<26;++i) {
ll cnt=n*(n+1)/2;
auto pos=a[i];
int len=pos.size();
ll l=0;
for(ll i=0;i<len;++i) {
ll r=pos[i]-1;
cnt-=(r-l+1)*(r-l+2)/2;
l=pos[i]+1;
}
ll r=n-1;
cnt-=(r-l+1)*(r-l+2)/2;
ans+=cnt;
}
cout<<ans;
}
最长回文子串
thinking
1000的数据量,我们可以直接暴力做,不过用区间dp,好像也是\(O(n^2)\),不是很理解。不过,暴力也能过就离谱。。。
solution
class Solution {
public:
bool ok(int left,int right,string &s) {
while(left<right) {
if(s[left]==s[right]) {
++left;
--right;
}else {
return false;
}
}
return true;
}
string longestPalindrome(string s) {
int n=s.size();
int l=0,r=0,cnt=1;
for(int i=0;i<n;++i) {
for(int j=i;j<n;++j) {
if(ok(i,j,s)&&(j-i+1>cnt)) {
l=i;r=j;
cnt=r-l+1;
}
}
}
return s.substr(l,r-l+1);
}
};
括号生成
thinking
数据量只有8?dfs爆搜(连回溯都没有?原谅我水个题)
solution
class Solution {
public:
vector<string> ans;
void dfs(string last,int left,int right,int cnt) {
if(cnt==0) {
ans.push_back(last);
return;
}
if(left==0) {
dfs(last+")",left,right-1,cnt-1);
} else {
dfs(last+"(",left-1,right,cnt-1);
if(right>left)
dfs(last+")",left,right-1,cnt-1);
}
}
//left right 表示的是剩余的括号
vector<string> generateParenthesis(int n) {
dfs("",n,n,2*n);
return ans;
}
};

浙公网安备 33010602011771号