题意:
给你两个字符串 和 ,字符串由小写字母组成,长度都为4,现在给你一种操作方法,每次操作你可以选择3个位置将其分别 "加上" 2,3,5,即 ,现在问你 最少操作 几次可以将 变成 ?
解法1:广度优先搜索
我们以每个长度为4的字符串作为点,每个字符串与其经过一次操作后变换成的字符串所代表的点连边,边权为1,用此方法构造隐式图,最后答案为起点 到终点 的最短路径。
由于图中每条边权都为1,故直接跑广度优先搜索即可求出答案。
代码:
class Solution { public: int solve(string s1, string s2) { queue<string> que; unordered_map<string,bool> vis;//vis[s]表示字符串s所代表的点是否扩展过 que.push(s1); vis[s1]=true; unordered_map<string,int> dis;//dis[s]表示字符串s1所代表的点到字符串s所代表的点的最短路径 while(!que.empty()){ string u=que.front(); que.pop(); if(u==s2)return dis[u]; for(int i=0;i<4;i++){//枚举不操作的位置 string t=u; int now=2; for(int j=0;j<4;j++){//将剩下3个位置进行变换 if(i==j)continue; t[j]=(t[j]-'a'+now)%26+'a'; if(now==2)now=3; else now=5; } if(vis[t])continue; que.push(t); vis[t]=true; dis[t]=dis[u]+1; } } return 0; } };
时间复杂度: ,k表示字符集大小,本题为26,显然此隐式图的点数为 级别的,每个点都只会扩展一次,故时间复杂度为
空间复杂度: ,每个字符串长度为4,可看成一个常数,总共有个点,要存储每个点是否扩展过和每个点的最短路径,故空间复杂度为
解法2:枚举每个位置的固定次数
题目意思是每次操作都固定1个位置不动,其余3个位置依次变化2、3、5,那么我们可以考虑写四重循环枚举每个位置的不动的次数,然后每种情况都分别计算出每个位置 "加" 的值,然后再比较按照此方法是否可以让 变成 。最后取出答案的最小值即可。
具体的:
我们分别设 不动的次数为
我们再分别设 "加"的值为
- 考虑固定位置0的贡献:
- 考虑固定位置1的贡献:
- 考虑固定位置2的贡献:
- 考虑固定位置3的贡献:
结合上述,可得:
考虑枚举每种情况,操作的总次数就是不动的总次数,即 ,最后答案取每次操作总次数的最小值即可。
代码:class Solution { public: int solve(string s1, string s2) { int cnt[4]={0}; for(int i=0;i<4;i++){ cnt[i]=(s2[i]-s1[i]+26)%26;//s1到s2每个位置的差值 } int ans=26*26*26*26; for(int a=0;a<=26;a++){//第0个位置固定的次数 for(int b=0;b<=26;b++){//第1个位置固定的次数 for(int c=0;c<=26;c++){//第2个位置固定的次数 for(int d=0;d<=26;d++){//第3个位置固定的次数 int c0=(b+c+d)*2;//只要第0个位置没有固定,加的值肯定是2 //第1个位置只能是加2或者3 //加2:第0个位置固定了多少次就加多少次2 //加3:第0个和第1个都没有固定,剩下第2个和第3个固定的次数和就是加3的次数 int c1=2*a+3*(c+d); //第2个位置只能是加3或者加5 int c2=3*(a+b)+5*d; //第3个位置只能加5 int c3=(a+b+c)*5; c0%=26; c1%=26; c2%=26; c3%=26; if(c0==cnt[0]&&c1==cnt[1]&&c2==cnt[2]&&c3==cnt[3]){ ans=min(ans,a+b+c+d); } } } } } return ans; } };
时间复杂度: ,为字符集大小,本题为26,由于我们枚举每个位置不动的次数为次,总共有4个位置,故时间复杂度为
空间复杂度: ,由于字符串长度仅为4,故我们只需要 级别的数组记录每个位置"加"的相关信息,故空间复杂度为