一:Minimum Size Subarray Sum(最小长度子数组的和O(N))
题目:
Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead.
For example, given the array [2,3,1,2,4,3]
and s = 7
,
the subarray [4,3]
has the minimal length under the problem constraint.
分析:一开始我采用的是LIS(longest increased sequence)中的最长递增子序列中的动态规划的思想,能通过,但是时间复杂度为O(N
^2);;;第二种方法是采用双指针+滑动窗口的思想,时间复杂度为O(N), 严格意义上说是2N,,比如 [1,2,3,15,3,4,5,15] s=14,,,只有在15处将前面的元素又重新加了一遍,故为2N
初始快慢指针都为0,fast指针向前移动,当slow和fast中连续字数组的和大于s时,我们就开始缩减窗口,不断的对slow进行向前移动直到sum小于s,然后再移动fast继续循环
代码:
class Solution {
public:
// 法一
/*int minSubArrayLen(int s, vector& nums) {
int result = nums.size();
bool flag = false;
for(int i = 0; i < nums.size(); i++){
if(nums[i] >= s) return 1;
int sum = nums[i];
for(int j = i-1; j >= 0; j--){
sum += nums[j];
if(sum >= s){
result = min(result, i-j+1);
flag = true;
break;
}
}
}
if(flag)return result;
return 0;
}*/
int minSubArrayLen(int s, vector& nums) { // 滑动窗口的形式+双指针
int result = nums.size()+1;
int frontPoint = 0, sum = 0;
for(int i = 0; i < nums.size(); i++){
sum += nums[i];
while(sum >= s){ // 找到了窗口
result = min(result, i - frontPoint + 1); // 窗口是否满足要求
sum -= nums[frontPoint++]; // 缩减窗口
}
}
return result == (nums.size()+1) ? 0:result;
}
};
二:Minimum Window Substring
题目:
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC"
.
Note:
If there is no such window in S that covers all characters in T, return the emtpy string ""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
分析:这道题刚开始我采用类似于上面滑动窗口的方法,但是每次都要判断当前字符串中是否完全包含字符串t,这个判断就会提升时间复杂度,结果导致TLE。后面参看了discuss中的方法,非常巧妙,也放在这里。代码中map用来存放t字符串中的字符及出现的次数,而window用来存放字符串t中每个字符在字符串s中出现的次数。lettercounts是一个标记变量,当等于t.size()的时候,就表示得到了一个完全包含t的字符子串,然后移动慢指针缩减窗口。代码:
TLE:
class Solution {
public:
bool isContain(const string &sstr, const string &t){
for(int i = 0; i < t.size(); i++){
if(sstr.find_first_of(t[i]) == string::npos) return false;
}
return true;
}
string minWindow(string s, string t) {
int result = s.size()+1, frontPoint = 0;
string str="";
for(int i = 0; i < s.size(); i++){
while(isContain(s.substr(frontPoint, i-frontPoint+1) , t)){
if(result > i-frontPoint+1){
result = i-frontPoint+1;
str = s.substr(frontPoint, i-frontPoint+1);
}
frontPoint++;
}
}
return str;
}
};
class Solution {
public:
string minWindow(string s, string t) {
string result;
if(s.size() == 0 || t.size() == 0) return result;
unordered_map map;
unordered_map window; // 滑动窗口
int lettercounts = 0; // 标记变量,当等于t.size()的时候,该窗口就是一个完全包含字符串t的子串
int minLen = s.size()+1;
for(int i = 0; i < t.size(); i++) // 将t放入map中,就是为了加速
map[t[i]]++;
for(int fast = 0, slow = 0; fast < s.size(); fast++){ // 快慢指针,快指针不断向前移动,
char c = s[fast];
if(map.find(c) != map.end()){ //
window[c]++;
if(window[c] <= map[c]){ // 变化lettercount变量
lettercounts ++;
}
if(lettercounts >= t.size()){ // 表示该窗口中已经全部包含t了
while(map.find(s[slow]) == map.end() || window[s[slow]] > map[s[slow]]){ // 对窗口进行缩减 1:slow所指向字符不在map中,2:在该子串中 //出现很多次 如BBABC ABC slow指向B
window[s[slow]]--;
slow++;
}
if(minLen > fast - slow + 1){
minLen = fast - slow + 1;
result = s.substr(slow, minLen);
}
window[s[slow]]--; // 缩减窗口
slow++;
lettercounts --;
}
}
}
return result;
}
};
三:Contains Duplicate III
题目:
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
分析:这道题目也是滑动窗口,滑动窗口一般都是定义一个slow指针,然后一个fast指针不断向前滑动(循环遍历),这个过程中我们要判断1:是否找到了窗口,2:窗口时否满足要求 3:窗口缩减等
此题也是,设置慢指针l,和快指针i遍历,窗口过大就缩减,判断找到的窗口是否满足要求,技巧是用到了关联容器的lower_bound函数,如果满足要求就返回true,否则返回false。这里用set或者multiset都一样.。。注意这里的auto是c++11的新特性,可以用来自动类型推断!
class Solution {
public:
/*bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) {
if(nums.size() < 2 || k == 0) return false;
multiset windows; // 滑动窗口
int l = 0;
for(int i = 0; i < nums.size(); i++){
if(i - l > k){ // 窗口大小超过了k 则需要删除nums[l]并且l++
windows.erase(nums[l++]);
}
auto it = windows.lower_bound((long)nums[i] - (long)t);
if(it != windows.end() && *it <= ((long)nums[i]+(long)t)) // 用long防止+1溢出
return true;
windows.insert(nums[i]);
}
return false;
}*/
bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) {
if(nums.size() < 2 || k == 0) return false;
set windows; // 滑动窗口
int l = 0; // 慢指针
for(int i = 0; i < nums.size(); i++){
if(i - l > k){ // 窗口大小超过了k 则需要删除nums[l]并且l++ 窗口需要缩减了
windows.erase(nums[l++]);
}
auto it = windows.lower_bound((long)nums[i] - (long)t); // 即为nums[i]-t与nums[i]+t之间是否有元素
if(it != windows.end() && *it <= ((long)nums[i]+(long)t)) // 用long防止+1溢出 找到了
return true;
windows.insert(nums[i]); // not found
}
return false;
}
};