问题描述
小U 和 小R 各自拥有一个长度相等的二进制字符串 A 和 B。现在,他们想要将这两个字符串修改成相同的字符串。每次修改可以选择以下两种操作:
交换同一个字符串中的任意两个字符,交换操作的成本为它们索引之差的绝对值 |i - j|。 对某个字符进行取反操作,取反的成本为 2。 小U 和 小R 想知道,将字符串 A 和 B 修改为相同字符串的最小总成本是多少?
思路
首先,考虑所有A,B不同的字符,易得在最优的答案中,每一个字符不可能被操作多余一次,并且当在i,j的字符距离大于等于四时,总是可以通过将两者取反获得不弱于置换的结果。
不妨让+1,-1分别表示A和B字符的两种可能不匹配,0表示A和B这一位匹配。
考虑字符串最后一个不同字符的处理方式,则分类讨论可以发现,当且仅当最后四位是以下情况时,将最后一位和之前的某一位置换要优于取反:
- ? ? -1 +1
- ? -1 0 +1
- -1 0 0 +1
- -1 -1 +1 +1
其余情况直接取反最后一位要由于置换。 所以不断重复以上操作,我们便可得到答案。
代码示例
int solution(const std::string& str1, const std::string& str2) {
if(!str1.size()) {
return 0;
}
string s1 = "0000"+str1;
string s2 = "0000"+str2;
vector<int> dp(s1.size(),0);
for(int i=4;i<s1.size();i++) {
dp[i] = dp[i-1] + 2;
if(s1[i]==s2[i]) {
dp[i] = dp[i-1];
} else if(s1[i-1]!=s2[i-1]&&s1[i-1]!=s1[i]) {
dp[i] = min(dp[i],dp[i-2] + 1);
} else if(s1[i-1]==s2[i-1]&&s1[i-2]!=s2[i-2]&&s1[i-2]!=s1[i]) {
dp[i] = min(dp[i],dp[i-3] + 2);
} else if(s1[i-1]==s2[i-1]&&s1[i-2]==s2[i-2]&&s1[i-3]!=s2[i-3]&&s1[i-3]!=s1[i]) {
dp[i] = min(dp[i],dp[i-4] + 3);
}
else if(s1[i-1]!=s2[i-1]&&s1[i-1]==s1[i]&&s1[i-2]!=s2[i-2]&&s1[i-2]!=s1[i]&&s1[i-3]!=s2[i-3]&&s1[i-3]!=s1[i]) {
dp[i] = min(dp[i],dp[i-4] + 4);
}
cout << dp[i] <<" ";
}
return dp[s1.size()-1];
}
代码示例
int solution(const std::string& str1, const std::string& str2) {
if(!str1.size()) {
return 0;
}
string s1 = "0000"+str1;
string s2 = "0000"+str2;
vector dp(s1.size(),0);
for(int i=4;i<s1.size();i++) {
dp[i] = dp[i-1] + 2;
if(s1[i]==s2[i]) {
dp[i] = dp[i-1];
} else if(s1[i-1]!=s2[i-1]&&s1[i-1]!=s1[i]) {
dp[i] = min(dp[i],dp[i-2] + 1);
} else if(s1[i-1]==s2[i-1]&&s1[i-2]!=s2[i-2]&&s1[i-2]!=s1[i]) {
dp[i] = min(dp[i],dp[i-3] + 2);
} else if(s1[i-1]==s2[i-1]&&s1[i-2]==s2[i-2]&&s1[i-3]!=s2[i-3]&&s1[i-3]!=s1[i]) {
dp[i] = min(dp[i],dp[i-4] + 3);
}
else if(s1[i-1]!=s2[i-1]&&s1[i-1]==s1[i]&&s1[i-2]!=s2[i-2]&&s1[i-2]!=s1[i]&&s1[i-3]!=s2[i-3]&&s1[i-3]!=s1[i]) {
dp[i] = min(dp[i],dp[i-4] + 4);
}
cout << dp[i] <<" ";
}
return dp[s1.size()-1];
}