问题描述
小U和小R有两个字符串,分别是SS和TT,现在小U需要通过对SS进行若干次操作,使其变成TT的一个前缀。操作可以是修改SS的某一个字符,或者删除SS末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让SS变成TT的前缀。
public class Main {
public static int solution(String S, String T) {
int minOperations = 0;
int lenS = S.length();
int lenT = T.length();
// 1. 如果 S 的长度大于 T 的长度,删除 S 的末尾字符
if (lenS > lenT) {
minOperations += lenS - lenT;
S = S.substring(0, lenT); // 删除多余的字符
}
// 2. 逐字符比较 S 和 T
for (int i = 0; i < S.length(); i++) {
if (S.charAt(i) != T.charAt(i)) {
// 3. 如果字符不匹配,需要修改字符
minOperations++;
}
}
return minOperations;
}
public static void main(String[] args) {
System.out.println(solution("aba", "abb") == 1);
System.out.println(solution("abcd", "efg") == 4);
System.out.println(solution("xyz", "xy") == 1);
System.out.println(solution("hello", "helloworld") == 0);
System.out.println(solution("same", "same") == 0);
}
}
解题思路
-
比较字符串长度:如果
S的长度大于T的长度,那么我们需要删除S的末尾字符,直到S的长度等于T的长度。 -
逐字符比较:从字符串的开头开始,逐字符比较
S和T,直到遇到第一个不匹配的字符。 -
计算操作次数:
- 如果
S和T在某个位置的字符不匹配,那么我们需要修改S的这个字符。 - 如果
S的长度大于T的长度,那么我们需要删除S的末尾字符。
- 如果
关键步骤解释
- 删除多余字符:如果
S的长度大于T,我们需要删除S的末尾字符,直到S的长度等于T。 - 逐字符比较:从字符串的开头开始,逐字符比较
S和T,直到遇到第一个不匹配的字符。 - 计算操作次数:每次遇到不匹配的字符,操作次数加一。
前缀和的技巧与应用
前缀和是一种高效处理数组相关问题的技巧,尤其适用于求取子数组的和、频率统计等场景。通过将原数组转化为前缀和数组,我们可以显著提高某些计算的效率。以下是对前缀和的基本概念、技巧和应用实例的深入探讨。
一、前缀和的基本概念
前缀和定义为数组中每个元素到该元素为止的所有元素之和。给定一个数组 nums,其前缀和数组 prefixSum 的定义如下:
- ( prefixSum[i] = nums[0] + nums[1] + ... + nums[i] )
构建前缀和数组
构建前缀和数组的时间复杂度为 O(n),可以用以下代码实现:
vector<int> computePrefixSum(vector<int>& nums) {
int n = nums.size();
vector<int> prefixSum(n + 1, 0);
for (int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
return prefixSum;
}
二、前缀和的应用技巧
-
快速求取子数组和: 使用前缀和可以在 O(1) 的时间内计算某个子数组的和。对于数组
nums中的任意子数组nums[l...r],其和可以表示为:[ sum(l, r) = prefixSum[r + 1] - prefixSum[l] ]
例如:
int rangeSum(vector<int>& prefixSum, int l, int r) { return prefixSum[r + 1] - prefixSum[l]; } -
处理复杂查询: 在某些查询问题中,前缀和数组可以与其他数据结构一起使用,例如差分数组,能简化问题并提高效率。
-
解决区间问题: 在有些题目中,可通过前缀和判断数组中某个区间内某种条件是否成立,比如子数组的最大和大于某个值等。
-
优化暴力法: 对于某些要求频繁计算子数组和的问题,暴力法的时间复杂度是 O(n^3),而应用前缀和可以将复杂度降低到 O(n^2)。
三、实际应用示例
示例:最大平均子数组
假设给定数组 nums,找出其中平均值最大且长度为 K 的子数组。利用前缀和进行求解可以简化过程。
double findMaxAverage(vector<int>& nums, int k) {
int n = nums.size();
vector<int> prefixSum = computePrefixSum(nums);
double maxAvg = INT_MIN;
for (int i = 0; i <= n - k; i++) {
double avg = (prefixSum[i + k] - prefixSum[i]) / static_cast<double>(k);
maxAvg = max(maxAvg, avg);
}
return maxAvg;
}
四、总结
前缀和是一种强大的技巧,能有效地优化多种数组相关问题的计算。通过快速构建前缀和数组并利用其性质,我们可以将原本复杂的 O(n^2) 甚至 O(n^3) 的操作降低到 O(n)。在算法解题中,灵活应用前缀和能够提高代码的效率,简化问题的复杂度,充分发挥计算机的优势。
通过这些深入的了解与应用,我们可以在面对数组和子数组等问题时,迅速而有效地找到解决方案。前缀和不仅仅是一种技巧,更是处理数据时的一种思维方式。