先给题
尽可能使字符串相等
给你两个长度相同的字符串,s 和 t。
将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/get-equal-substrings-within-budget
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
有兴趣的可以先做一下
本人用的C++的代码
1.首先先说暴力破解(这是我的第一想法,很蠢,但还是要写出来) 我首先想到的是从第一位开始,依次进行比较,超出最大则从记录的地址(a)值下一位开始
1 class Solution { 2 3 public: 4 int equalSubstring(string s, string t, int maxCost) { 5 int sum = 0; 6 int min = 0, n = 0;//min 记录最大的长度 n 记录当前长度 7 int a = 0;//用来记录地址 8 for (int i = 0; i < s.length(); i++) { 9 n++; 10 sum += abs((int)(s[i] - t[i])); 11 if (sum > maxCost) { 12 i = ++a; 13 n--; 14 min = n > min ? n : min; 15 n = 0; 16 sum = 0; 17 } 18 } 19 //如果字符串最后一位正好达到max 还需要在进行一次比较 20 return (n > min ? n : min); 21 } 22 };
毫无疑问,暴力破解是超时的,那么接下来就得优化过程,我想的是让地址值a的移动进行一些适当的改变。
在优化过程中,我看了一下题解,这时恍然大悟,可以转换一下,转换成自己做过的题目。
我们可以把s和t第i个字符ASCII 码值的差的绝对值先算出来,存储在一个数组中,这样问题就转换成了最大子数组问题(只不过加了一些限制,没有负数和有最大上限)。
算法导论p38-p42 有对最大子数组的描述,分治法和一个线性时间的算法。(以此为参考来讨论这个题)
可以观看我的博客,我对最大子数组问题也进行过分析。
这是我根据转化后的数组进行的一个修改,虽然通过了,但是时间还是很长,只能说勉强过了,我先解释一下我的这个代码,交代一下我的思路,然后再说我从其他博客以及题解中获得的思想
1 class Solution { 2 public: 3 int equalSubstring(string s, string t, int maxCost) { 4 int length = s.length(); 5 int* num = new int[length + 1]; 6 for (int i = 1; i < length + 1; i++) { 7 num[i] = abs((int)(s[i - 1] - t[i - 1])); 8 cout << num[i] << " "; 9 } 10 int sum = 0, maxsum = 0; 11 int low = 0; 12 int maxlow = 0, maxhigh = 0; 13 for (int i = 1; i <= length; i++) { 14 sum += num[i]; 15 while (sum > maxCost) 16 { 17 low++; 18 sum -= num[low]; 19 } 20 if (((i - low) > (maxhigh - maxlow))) 21 { 22 maxhigh = i; 23 maxlow = low; 24 maxsum = sum; 25 } 26 } 27 return maxhigh - maxlow; 28 } 29 };
这是暴力破解的一个改良版,让判定的sum值更少了一些(我忽略了本题想要解的东西,本题只想解出最大长度,而我却一直在纠结最大子数组是哪个)
我们直接举例子来说明我的代码吧
假设1 2 3 的总值是小于maxCost的 而 1 2 3 4的总值是大于maxCost的,那么接下来我们就要让它减小到maxCost即让low++ 缩减到2 3 4,判断是否达到最小(等会看后面的讲解这一步其实是没必要循环的)
如果长度大于我们记录的最大长度,那么替换相应的值即可。
相比较暴力破解,我们省去了2 和 3 和 2 3 这样的比较过程。
https://leetcode-cn.com/problems/get-equal-substrings-within-budget/solution/shuang-zhi-zhen-hua-dong-chuang-kou-by-c-3ktr/
https://leetcode-cn.com/problems/longest-repeating-character-replacement/solution/ti-huan-hou-de-zui-chang-zhong-fu-zi-fu-eaacp/
以上是参考
其实我的想法和答案很接近了,但唯一差出的就是判断sum>maxCost时,我一直想要让sum的值降下来,好求最大子数组坐标,但本题并没有让你去求这个坐标,只需要知道长度即可,
那么改为if的话,如果大于maxCost low++ 我们所记录的最大的长度是没有改变的,只有当sum<=maxCost时,长度才会增加,所以我们没必要让sum始终<=maxCost,只要保证最后的是最大长度即可。
那么接下来修改代码
1 int equalSubstring(string s, string t, int maxCost) { 2 int length = s.length(); 3 int* num = new int[length + 1]; 4 for (int i = 1; i < length + 1; i++) { 5 num[i] = abs((int)(s[i - 1] - t[i - 1])); 6 } 7 int sum = 0; 8 int low = 1; 9 int i = 1; 10 for (; i <= length; i++) { 11 sum += num[i]; 12 if (sum > maxCost) 13 { 14 sum -= num[low]; 15 low++; 16 } 17 } 18 return i - low; 19 }
这是修改后的代码,耗时还是长,应该是开辟数组的缘故,我们就不开辟数组了。
1 int equalSubstring(string s, string t, int maxCost) { 2 int length = s.length(); 3 int sum = 0; 4 int low = 0; 5 int i = 0; 6 for (; i < length; i++) { 7 sum += abs((int)(s[i] - t[i])); 8 if (sum > maxCost) 9 { 10 sum -= abs((int)(s[low] - t[low])); 11 low++; 12 } 13 } 14 return i - low; 15 }
速度与内存都得到了改善。