同向双指针是经常考的一种题型;
什么时候用?
发现题目,两个指针,只要固定一个,另外一个扫描,总是有坏坏坏,突然变好,不再回来
或者好好好,忽然变坏,不再回来,那么就是同向双指针算法,基本上都是O(n)的算法复杂度;
写程序注意的点:
固定i,i是主指针每次走一步,写for循环,j是辅指针,写while循环,每次可能走N步;
Minimum Size Subarray Sum
给定一个由 n
个正整数组成的数组和一个正整数 s
,请找出该数组中满足其和 ≥ s 的最小长度子数组。如果无解,则返回 -1。
Example
样例 1:
输入: [2,3,1,2,4,3], s = 7
输出: 2
解释: 子数组 [4,3] 是该条件下的最小长度子数组。
样例 2:
输入: [1, 2, 3, 4, 5], s = 100
输出: -1
思路:主指针i每次走一步,j每次走N步,i用for,j用while循环;每次用j滑动到找到>=s的地方,更新 length,i++ 同时sum - nums[i];
public class Solution {
/**
* @param nums: an array of integers
* @param s: An integer
* @return: an integer representing the minimum size of subarray
*/
public int minimumSize(int[] nums, int s) {
if(nums == null || nums.length == 0) {
return -1;
}
int sum = 0;
int j = 0;
int res = Integer.MAX_VALUE;
// 主指针i每次走一步,j每次走N步,i用for,j用while循环;
// 注意每次判断求最大还是求最小;弄清楚之后,才能够赋初值,因为要min or max;
for(int i = 0; i < nums.length; i++) {
while(j < nums.length && sum < s) {
sum += nums[j];
j++;
}
if(sum >= s) {
res = Math.min(res, j - i);
// 踢掉i所对应的值;
sum -= nums[i];
}
}
// 特殊情况判断,如果res 没变,代表根本没找到 return -1;
if(res == Integer.MAX_VALUE) {
return -1;
}
return res;
}
}
Minimum Window Substring
给定两个字符串 source
和 target
. 求 source
中最短的包含 target
中每一个字符的子串.
Example
样例 1:
输入: source = "abc", target = "ac"
输出: "abc"
样例 2:
输入: source = "adobecodebanc", target = "abc"
输出: "banc"
解释: "banc" 是 source 的包含 target 的每一个字符的最短的子串.
思路:也是同向双指针,只是多了个count char的过程,注意要count的数目满足了target里面char的数目才算集齐一种char;
后面i挪动的时候,也要去掉char count同时需要判断是否少于target char count,代表少集齐一种char;
public class Solution {
/**
* @param source : A string
* @param target: A string
* @return: A string denote the minimum window, return "" if there is no such a string
*/
public String minWindow(String source , String target) {
if(source == null || target == null) {
return null;
}
char[] ss = source.toCharArray();
char[] tt = target.toCharArray();
int[] scount = new int[256];
int[] tcount = new int[256];
int now = 0;
int K = 0;
// collect target information;
for(int i = 0; i < tt.length; i++) {
tcount[tt[i]]++;
if(tcount[tt[i]] == 1) {
K++;
}
}
int resl = 0; int resr = 0;
int windowSize = Integer.MAX_VALUE;
int j = 0;
// 同向双指针模板;
for(int i = 0; i < ss.length; i++) {
while(j < ss.length && now < K) {
scount[ss[j]]++;
if(tcount[ss[j]] != 0 && scount[ss[j]] == tcount[ss[j]]){
now++;
}
j++;
}
//while循环之后都是判断是否满足条件更新global值;
if(now == K) {
if(j - i < windowSize) {
resl = i;
resr = j;
windowSize = j - i;
}
}
// 这里j == ss.length的情况,还要等i继续remove,
// 因为是要找最短,有可能i继续remove,还是满足C == K的情况,这样最短的还可以继续缩进;
// remove i, need to remove scount and C-- if below tcount
scount[ss[i]]--;
if(scount[ss[i]] < tcount[ss[i]]) {
now--;
}
}
return source.substring(resl, resr);
}
}
Longest Substring Without Repeating Characters
给定一个字符串,请找出其中无重复字符的最长子字符串。
Example
样例 1:
输入: "abcabcbb"
输出: 3
解释: 最长子串是 "abc".
样例 2:
输入: "bbbbb"
输出: 1
解释: 最长子串是 "b".
思路:同向双指针, i是主指针,j是辅指针;主指针写for循环,j一直移动写while循环;
当移动到有重复值的时候,update len (j-i), 注意 int count array 的index就是char;
public class Solution {
/**
* @param s: a string
* @return: an integer
*/
public int lengthOfLongestSubstring(String s) {
if(s == null || s.length() == 0) {
return 0;
}
char[] ss = s.toCharArray();
int[] count = new int[256];
int maxlen = 0;
int j = 0;
for(int i = 0; i < ss.length; i++) {
while(j < ss.length && count[ss[j]] == 0){
count[ss[j]]++;
j++;
}
// update maxlen;
maxlen = Math.max(maxlen, j - i);
// move i, update count;
count[ss[i]]--;
}
return maxlen;
}
}
Longest Substring with At Most K Distinct Characters
给定字符串S,找到最多有k个不同字符的最长子串T。
Example
样例 1:
输入: S = "eceba" 并且 k = 3
输出: 4
解释: T = "eceb"
样例 2:
输入: S = "WORLD" 并且 k = 4
输出: 4
解释: T = "WORL" 或 "ORLD"
思路:跟 Longest Substring with at Most 2 Characters.思路一模一样。i是主指针,j是辅指针,然后模板套起来,注意要判断如果即将要大于k的时候,j停下来,不做任何事情,update res,然后i++;
public class Solution {
/**
* @param s: A string
* @param k: An integer
* @return: An integer
*/
public int lengthOfLongestSubstringKDistinct(String s, int k) {
if(s == null || s.length() == 0 || k <= 0) {
return 0;
}
char[] ss = s.toCharArray();
int[] scount = new int[256];
int count = 0;
int res = 0;
int j = 0;
// 同向双指针模板;
for(int i = 0; i < s.length(); i++) {
while(j < s.length() && count <= k) {
// j move到即将要超过k的时候,停下来,scount[ss[j]]不做任何事情;
// 等待下一次while循环,j就可以update了;
if(scount[ss[j]] == 0) {
if(count == k){
break;
}
count++;
}
scount[ss[j]]++;
j++;
}
res = Math.max(res, j - i);
//update i;
scount[ss[i]]--;
if(scount[ss[i]] == 0) {
count--;
}
}
return res;
}
}
Longest Substring with At Most Two Distinct Characters
给定一个字符串,找出最长子串TT的长度,它最多包含2
个不同的字符。
思路:跟上题一模一样,只是把K变成2即可;
public class Solution {
/**
* @param s: a string
* @return: the length of the longest substring T that contains at most 2 distinct characters
*/
public int lengthOfLongestSubstringTwoDistinct(String s) {
if(s == null || s.length() == 0) {
return 0;
}
char[] ss = s.toCharArray();
int[] scount = new int[256];
int count = 0;
int res = 0;
int j = 0;
// 同向双指针模板;
for(int i = 0; i < s.length(); i++) {
while(j < s.length() && count <= 2) {
// j move到即将要超过k的时候,停下来,scount[ss[j]]不做任何事情;
// 等待下一次while循环,j就可以update了;
if(scount[ss[j]] == 0) {
if(count == 2){
break;
}
count++;
}
scount[ss[j]]++;
j++;
}
res = Math.max(res, j - i);
//update i;
scount[ss[i]]--;
if(scount[ss[i]] == 0) {
count--;
}
}
return res;
}
}