LeetCode技巧篇(二)Two points for Sliding Window 滑动窗口中的双指针

介绍

双指针是LeetCode里面非常实用并且常用的一种技巧,而且有应用的范围也很广。比如二分法(binary search)也可以看成是左右两个指针缩小搜索范围,确定最终结果快慢指针确定链表是不是含有环;等等。不过这里笔者介绍用在滑动窗口结合双指针的技巧。下面先引入一个简单的例子:LeetCode 3,难度中等,要求找到无重复字符的最长子串。
在这里插入图片描述
那么对于上述的字符串来说最长的无重复字符的子串是abc(其中的一种),所以长度是3。那么最直观的就是暴力搜索,用一个map或者set存储遍历到的字符,如果出现重复的话就退出,然后比较长度。
但是这样的解法显然时间复杂度太高。我们可以尝试构建一个窗口,判断这个窗口是否满足要求;如果满足要求,那么缩小窗口;如果不满足要求,继续往前滑动。重复以上操作,得到最终的结果。
在这里插入图片描述
那么这类问题的核心代码就是:

//定义左右指针
int left = 0, right = 0;
while(right<s.length()){
	//窗口添加元素,且right指针往右前进
	while(meet){
		//窗口里面的元素减少,且left指针向右前进
	}
}

实例

可以用滑动窗口双指针解决的leetcode问题有:LeetCode 3,LeetCode 713, LeetCode 438,LeetCode 159。
LeetCode 3的代码如下:

    public int lengthOfLongestSubstring(String s) {
        char ch[] = s.toCharArray();
        HashMap<Character, Integer> map = new HashMap();
        int left=0, right=0,ans=0;
        while(right<s.length()){
            char c1 = ch[right++];
            map.put(c1, map.getOrDefault(c1,0)+1);
            while(map.get(c1)>1){
                char c2 = ch[left];
                map.put(c2, map.get(c2)-1);
                left++;
            }
            ans = Math.max(ans,right-left);
        }
        return ans;
    }

LeetCode 713,这题比较简单,要求找到乘积小于k的连续子数组的个数。

    public int numSubarrayProductLessThanK(int[] nums, int k) {
        if(k<=1) return 0; 
        int left =0, len =0,pro=1;
        for(int j=0;j<nums.length;j++){
            pro *=nums[j];
            while(pro>=k) pro/=nums[left++];
            len+=j-left+1;
        }
        return len;
    }

LeetCode 438,要求找到异位词的起始位置。所谓异位词,就是和模板字符串里出现的字符都一样,并且可以对应位置不同。比如abc的异位词可以是cba,cab等。

    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> list = new ArrayList();
        int[] arrS = new int[26];
        int[] arrP = new int[26];
        int count=0;
        for(char c:p.toCharArray()){
            arrP[c-'a']++;
            if(arrP[c-'a']==1) count++;
        }
        int left=0, right=0,match=0;
        while(right<s.length()){
            char c1 = s.charAt(right);
            if(arrP[c1-'a']>0){
                arrS[c1-'a']++;
                if(arrS[c1-'a']==arrP[c1-'a']) match++;
            }
            right++;
            while(match==count){
                if(right-left==p.length()){
                    list.add(left);
                }
                char c2 = s.charAt(left);
                if(arrP[c2-'a']>0){
                    arrS[c2-'a']--;
                    if(arrS[c2-'a']<arrP[c2-'a']) match--;
                }
                left++;
            }
        }
        return list;
    }

LeetCode 159,至多包含两个不同字符的最长子串,这个也是典型的滑动窗口问题:

    public int lengthOfLongestSubstringTwoDistinct(String s) {
        Map<Character,Integer> map = new HashMap();
        int maxL = 0;
        int left=0,right=0;
        while(right<s.length()){
            char c1 = s.charAt(right);
            map.put(c1, map.getOrDefault(c1,0)+1);
            while(left<=right&&map.size()>2){
                char c2= s.charAt(left);
                left++;
                if(map.get(c2)==1) map.remove(c2);
                else map.put(c2,map.get(c2)-1);
            }
            maxL = Math.max(maxL, right-left+1);
            right++;
        }
        return maxL;
    }

总结

当题目中出现字符串匹配连续子序列等字样的时候,如果只是简单的使用暴力解法,那么时间复杂度一般都会超过O( n 2 n^2 n2),这是可以考虑使用滑动窗口+双指针解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值