##尝试1
首先分析题目,发现题目要求的最长超赞字符串有点动态规划的味道,对超赞子字符串性质进行分析,感觉它可以转换成连续序列中元素出现次数的是偶数还是奇数的问题,这样进一步引导我们将问题做状态压缩,从而更好地进行dp计算。
假设s[i,j]是从i到j的子字符串,记t[i,j]为子字符串中0-9个数字出现的次数的奇偶性质,偶数次记为1,奇数次记为0,如果,s[i,j]为超赞子字符串,那么t[0,i-1]和t[0,j]具有一定关系,即子字符串0-i-1和子字符串0-j的所有数字奇偶性质是一样的或者只有一位数字的奇偶性质不一样。
为什么呢?
1.很容易证明,超赞子字符串中最多只有一个元素出现的次数为奇数,其余元素出现的次数为偶数。
2.t[0,j]和t[0,i-1]的实际上是由子串s[0]-s[j]中0-9出现的个数、子串s[0]-s[i-1]中0-9出现的个数决定的,我们需要证明的是子串s[0]-s[i-1]中0-9出现的个数,在加上子串s[i]-s[j]中0-9出现的个数后,奇偶性最多有一位是变化的。
3.任意取一个数字k,最多只有1位k在s[i]-s[j]的个数为奇数,假设k在s[i]-s[j]的个数刚好是奇数,再加上k在s[i]-s[j]的个数,k在子串s[0]-s[j]出现的个数奇偶性应该发生变化,即t[0,j]的第k位相对于t[0,i-1]应该发生变化;刚刚在1已经说过,”超赞子字符串中最多只有一个元素出现的次数为奇数,其余元素出现的次数为偶数“,取完第k位,其余位在s[i]-s[j]出现的个数应该为偶数,由于奇数+偶数=奇数,偶数+偶数=偶数,即任何一个数加上偶数奇偶性不变,显然t[0,j]相对于t[0,i-1]除了第k位,其他都不变,证明完成。
4.补充一下,如果s[i]-s[j]中所有的元素出现的次数都是偶数,那么t[0,i-1]==t[0,j]
上述通过上述推论可以获得状态迁移方程
dp[j]=max{j-k+1},(0<=k<=j)且必须满足二进制数t[0,k-1]和t[0,j]之间最多有一位不一样
dp[i]为s[0]-s[i]最大超赞字符串长度
而所求结果ans=dp[s.length()]
事实上可以省去dp数组,直接边遍历序列边更新ans
class Solution {
public:
int longestAwesome(string s) {
int jiou[100000+1];
int ans=0;
jiou[0]=0;
for(int i=0;i<s.length();i++)
{
int number=s[i]-'0';
jiou[i+1]=jiou[i];
int temp=1<<number;
jiou[i+1]=jiou[i+1]^temp;
for(int j=0;j<=i;j++)
{
if(jiou[i+1]==jiou[j])
ans=ans<i+1-j?i+1-j:ans;
}
int k=0;
while(k<10)
{
int t1=1<<k;
int t2=jiou[i+1]^t1;
for(int j=0;j<=i;j++)
{
if(t2==jiou[j])
ans=ans<i+1-j?i+1-j:ans;
}
k++;
}
}
return ans;
}
};//我的time_limit代码
很遗憾,上面代码时间复杂度太高为O(n²),运行超时导致wa
原因在于t[0,j]都需要找到一个t[0,i-1],由于我采取的是string数组的方式,从头到尾每一个字符串进行比较,直到找到第一个符合的字符串,这才确定i的值,时间浪费在遍历上
##解决
看完答案发现采用哈希表的方式能省去遍历找i的时间,只要确定了t[0,j],根据哈希映射关系直接确定i的位置
具体实现:
1.建立一个哈希表,键值对都为int类型,key对应t[0,i]的二进制数的值,value为i的位置
2.插入一个<0,-1>的元素,这个对应全部元素出现的次数均为偶数的情况
3.ans=0,对应结果;last=0,对应前一个序列的二进制值
4.从头到尾遍历s,i为位置变量,last=last^(1<<(s[i]-‘0’)),last为当前以i结尾序列t[0,i]的值,在哈希表中查找是否已经存在对应的key,如果存在,比较ans与i-value值大小,选最大的进行更新ans的值;如果不存在,则将last作为key,i作为value加入哈希表中。
5.尝试变换last所对应二进制数的某一位,注意last不能变(对应当前或者前一个序列的二进制值)同4一样,在哈希表中查找key-value对,如果存在,则按4一样更新ans,反之继续,无需更新哈希表。
6.最后所得ans为答案
class Solution {
public:
int longestAwesome(string s) {
int ans=0;
int last=0;
unordered_map<int,int> hash_table{{0,-1}};
for(int i=0;i<s.length();i++)
{
last=last^(1<<(s[i]-'0'));//获得key
if(hash_table.count(last))
ans=i-hash_table.at(last)>ans?i-hash_table.at(last):ans;
else
{
hash_table[last]=i;
}
for(int j=0;j<10;j++)
{
int temp=last^(1<<j);//获得key
if(hash_table.count(temp))
ans=i-hash_table.at(temp)>ans?i-hash_table.at(temp):ans;
}
}
return ans;
}
};//AC代码
博客内容讲述了如何使用动态规划和哈希表优化算法,解决寻找字符串中最长超赞子串的问题。初始方法由于时间复杂度过高导致运行超时,通过引入哈希表存储中间状态,减少了查找时间,从而提高了效率,最终实现了AC代码。
790

被折叠的 条评论
为什么被折叠?



