算法-双指针(java)

左右指针
leetcode 15. 三数之和

在这里插入图片描述

解题:

  • 首先对数组进行排序,排序后固定一个数nums[i],再使用左右指针指向nums[i]后面的两端,数字分别为nums[ L]和nums[R],计算三个数的和sum判断是否满足为0,满足则添加进结果集
  • 如果nums[i]大于0,则三数之和必然无法等于0,结束循环
  • 如果nums[i]==nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过
  • 当sum==0时,nums[L]==nums[L-1]则会导致结果重复,应该跳过,L++
  • 当 sum ==0时,nums[R]==nums[R-1]则会导致结果重复,应该跳过,R–
  • 时间复杂度:0(n2),n为数组长度
public List<List<Integer>> threeSum(int[] nums) {
        // 排序
        Arrays.sort(nums);
        ArrayList<List<Integer>> ans = new ArrayList<>();
        // 双指针
        for (int i = 0; i < nums.length; i++) {
            // 满足条件提前结束
            if (nums[i]>0) break;
            if (i!=0&&nums[i]==nums[i-1]){
                continue;
            }
            int L = i+1;
            int R = nums.length-1;
            while (L<R){
                int sum = nums[i]+nums[L]+nums[R];
                if (sum == 0 ){
                    ans.add(Arrays.asList(new Integer[]{nums[i],nums[L],nums[R]}));
                    while (L<R && nums[L]==nums[++L]){} //去重
                    while (L<R && nums[R]==nums[--R]){} //去重
                }else if(sum<0){
                    while (L<R && nums[L]==nums[++L]){}
                }else {
                    while (L<R && nums[R]==nums[--R]){}
                }
            }
        }
        return ans;
    }

参考:


滑动窗口
76. 最小覆盖子串

在这里插入图片描述
滑动窗口框架

public String minWindow(String s, String t){
        //目标计数
        HashMap<Character, Integer> target = new HashMap<>();
        //目标统计
        ……
        //滑动框内计数
        HashMap<Character, Integer> window = new HashMap<>();
        // 左右指针,左闭右开
        int L = 0, R = 0;
        while (R < s.length()){
            // 移入的元素
            Character cr = s.charAt(R);
            // 增大窗口
            R++;
            // 窗口内数据更新
            ……            
            // 只要窗口满足条件,就收缩
            while(窗口满足条件){
                //更新结果
                ……
                // 移出左边的元素
                Character cl = s.charAt(L);
                //缩小窗口,L++;
                L++;
                // 窗口内数据更新
            	……
            }
        }
        return 结果
    }

完整代码

public String minWindow(String s, String t){
        //目标计数
        HashMap<Character, Integer> target = new HashMap<>();
        //目标统计
        for(Character c:t.toCharArray()){
            target.put(c,target.getOrDefault(c,0)+1);
        }
        //滑动框内计数
        HashMap<Character, Integer> window = new HashMap<>();
        // 左右指针,左闭右开
        int L = 0, R = 0;
        // 达成目标个数累计(如果==target.size()表示window框包含所有目标中内容)
        int cnt=0;
        // 记录最小覆盖子串起始索引、长度
        int start = 0,res_len = Integer.MAX_VALUE;
        while (R < s.length()){
            // 移入的元素
            Character cr = s.charAt(R);
            // 增大窗口
            R++;
            // 判断移入的元素是否是target中元素
            if(target.containsKey(cr)){
                //增加window对应元素数量,注意window中可能没有cr Key,所以用getOrDefault
                window.put(cr,window.getOrDefault(cr,0)+1);
                // 加入元素可能使窗口接近目标,增加cnt计数
                if (window.get(cr).equals(target.get(cr))) cnt++;

            }
            // 只要窗口满足条件,就收缩
            while(cnt == target.size()){
                //更新结果
                if (R-L <res_len){
                    start = L;
                    res_len = R-L;
                }
                // 移出左边的元素
                Character cl = s.charAt(L);
                //缩小窗口,L++;
                L++;
                // 判断移出的元素是否和t中相同
                if(target.containsKey(cl)){
                    // 移出元素可能使窗口不满足条件
                    if (window.get(cl).equals(target.get(cl))) cnt--;
                    //减小window对应元素数量
                    window.put(cl,window.get(cl)-1);
                }
            }

        }
        return res_len==Integer.MAX_VALUE?"":s.substring(start,start+res_len);
    }

参考:labuladong的算法小抄

567. 字符串的排列

在这里插入图片描述
解答:

public boolean checkInclusion(String s1, String s2) {
        HashMap<Character, Integer> target = new HashMap<>();
        for (Character c : s1.toCharArray()){
            target.put(c,target.getOrDefault(c,0)+1);
        }
        HashMap<Character, Integer> window = new HashMap<>();
        int L=0,R=0;
        int cnt = 0;
        while (R <s2.length()){
            Character cr = s2.charAt(R);
            R++;
            // 进⾏窗⼝内数据的⼀系列更新
            if (target.containsKey(cr)){
                window.put(cr,window.getOrDefault(cr,0)+1);
                if (window.get(cr).equals(target.get(cr))) cnt++;
            }

            // 判断左侧窗⼝是否要收缩
            while (R - L >=s1.length()){
                // 在这⾥判断是否找到了合法的⼦串
                if (cnt == target.size()) return true;
                Character cl = s2.charAt(L);
                L++;
                // 进⾏窗⼝内数据的⼀系列更新
                if (target.containsKey(cl)){
                    if (window.get(cl).equals(target.get(cl))) cnt--;
                    window.put(cl,window.get(cl)-1);
                }
            }
        }
        // 未找到符合条件的⼦串
        return false;
    }
438. 找到字符串中所有字母异位词

在这里插入图片描述
解答:

public List<Integer> findAnagrams(String s, String p){
        HashMap<Character, Integer> target = new HashMap<>();
        for(Character c:p.toCharArray()){
            target.put(c,target.getOrDefault(c,0)+1);
        }
        HashMap<Character, Integer> window = new HashMap<>();
        ArrayList<Integer> res = new ArrayList<>();
        int L=0,R=0;
        int cnt=0;
        while (R <s.length()){
            Character cr = s.charAt(R);
            R++;
            if (target.containsKey(cr)){
                window.put(cr,window.getOrDefault(cr,0)+1);
                if (window.get(cr).equals(target.get(cr))) cnt++;
            }
            // 判断左侧窗⼝是否要收缩
            while (R-L >= p.length() ){
                Character cl = s.charAt(L);
                if (cnt == target.size()){
                    res.add(L);
                }
                L++;
                if (target.containsKey(cl)){
                    if (window.get(cl).equals(target.get(cl))) cnt--;
                    window.put(cl,window.get(cl)-1);
                }
            }
        }
        return res;
    }
3. 无重复字符的最长子串

在这里插入图片描述
解答

// 滑动窗口 11ms
    public int lengthOfLongestSubstring(String s){
        HashMap<Character, Integer> map = new HashMap<>();
        int L = 0,R = 0 ;
        int res = Integer.MIN_VALUE;
        while (R < s.length()){
            Character cr = s.charAt(R);
            R++;
            map.put(cr,map.getOrDefault(cr,0)+1);
            // 当 map.get(cr) 值⼤于 1 时,说明窗⼝中存在重复字符,不符合条件,就该L++缩⼩窗⼝
            while (map.get(cr)>1){
                Character cl = s.charAt(L);
                L++;
                map.put(cl,map.get(cl)-1);
            }
            // 更新无重复的 最长字串
            if (R - L >res ) res = R-L;
        }
        return res==Integer.MIN_VALUE?0:res;
    }

快慢指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值