目的
如何将嵌套for循环在少数问题中转换为单个for循环,从而减少了时间的复杂性。
实例
实例1
题目描述
给一组大小为n的整数数组,计算长度为k的子数组的最大值。
Input : arr[] = {100, 200, 300, 400}
k = 2
Output : 700
Input : arr[] = {1, 4, 2, 10, 23, 3, 1, 0, 20}
k = 4
Output : 39
We get maximum sum by adding subarray {4, 2, 10, 23} of size 4.
Input : arr[] = {2, 3}
k = 3
Output : Invalid
There is no subarray of size 3 as size of whole array is 2.
解题思路
(1)使用线性循环计算n个项中前k个元素的总和,并将总和存储在变量window_sum中。
(2)在阵列上应用滑动窗口技术线性滑动直至达到最终并同时追踪最大和。
(3)要获得k个元素块的当前总和,只需从前一个块中减去第一个元素并添加当前块的最后一个元素即可。
代码
int maxSum(int arr[], int n, int k)
{
if (n < k)
{
cout << "Invaild";
return -1;
}
int max_sum = 0;
for (int i=0; i<k; i++)
{
max_sum += arr[i];
}
int windows_sum = max_sum;
for (int i=k; i<n; i++)
{
windows_sum += arr[i] - arr[i - k];
max_sum = max(max_sum, windows_sum);
}
return max_sum;
}
实例2
题目描述
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。不考虑答案输出的顺序。
示例 1:
输入:
s: “cbaebabacd” p: “abc”
输出:
[0, 6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。
解题思路
(1)使用线性循环识别s的前p.length()个字符和p的所有字符并分别记录于sSave、pSave。
(2)判断子串是否与p是字母异位词。
(3)在字符串s上应用滑动窗口技术线性滑动直至达到字符串结束,每滑动一步都进行子串是否与p是字母异位词判断。
代码
vector<int> findAnagrams(string s, string p) {
vector<int>answer;
string s_sub;
if (p.length() > s.length()) {
return answer;
}
vector<int>sSave(26, 0), pSave(26, 0);
for (int i = 0; i < p.length(); i++) {
pSave[p[i] - 'a']++;
sSave[s[i] - 'a']++;
}
int index = 0;
if (pSave == sSave) {
// 判断子串是否与p是字母异位词
s_sub = s.substr(index, p.length());
if (s_sub != p) {
answer.push_back(index);
}
}
for (index = 1; index <(int)s.length() - (int)p.length() + 1; index++) {
sSave[s[index - 1] - 'a']--;
sSave[s[index + p.length() - 1] - 'a']++;
if (pSave == sSave) {
// 判断子串是否与p是字母异位词
s_sub = s.substr(index, p.length());
if (s_sub != p) {
answer.push_back(index);
}
}
}
return answer;
}
总结
现在,很明显时间复杂性是线性的,因为我们可以看到只有一个循环运行在我们的代码中。因此,我们的时间复杂度是O(n)。
我们可以使用这种技术来查找最大/最小k-子阵列,XOR,乘积,总和等