同向双指针算法题总结

同向双指针是经常考的一种题型;

什么时候用?

发现题目,两个指针,只要固定一个,另外一个扫描,总是有坏坏坏,突然变好,不再回来

或者好好好,忽然变坏,不再回来,那么就是同向双指针算法,基本上都是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;
    }
}
发布了562 篇原创文章 · 获赞 13 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/u013325815/article/details/103870979