12-08滑动窗口

 滑动窗口:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台





3. 无重复字符的最长子串

官解的滑动窗口非常易于理解,左指针每次+1,右指针从当前位置开始往后找,使用HashSet来排除重复元素

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 哈希集合,记录每个字符是否出现过
        Set<Character> occ = new HashSet<Character>();
        int n = s.length();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
                // 不断地移动右指针
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = Math.max(ans, rk - i + 1);
        }
        return ans;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/1959540/xia-biao-zong-suan-cuo-qing-kan-zhe-by-e-iaks/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

但是可以发现,使用一个一个滑的滑动窗口会有很多无效循环,比如abcddfghj,d出现重复,但是在abcd中的最后一位,一位一位的滑,会导致b、c、d开始的滑动其实都无意义。

改进:

*使用HashMap来记录当前遍历情况下的所有出现字母索引的最新情况,如果出现了一个字符在map中存在,判断这个字符的索引是否大于start,如果大于,说明是在当前的最大字符串中,所以从字符索引的下一字符重新开始,如果不在,则不管。

*比较当前字符串的长度和max的值,进行更新。

*将ch的索引值更新,保证它的索引为最新情况

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //用map记下每个字符的索引,直接跳转
        HashMap<Character,Integer> map=new HashMap<>();
        int n=s.length();
        int start=0;
        int ans=0;
        for(int end=0;end<n;end++){
            char ch=s.charAt(end);
            if(map.containsKey(ch)){
                start=Math.max(map.get(ch)+1,start);
            }
            ans=Math.max(ans,end-start+1);
            //替换掉ch的索引,每个ch的索引都是当前遍历情况下最新的
            map.put(ch,end);
        }
        return ans;

    }
}

438. 找到字符串中所有字母异位词

技巧:用整数数组来存储字母,易于比较,不用考虑字母顺序

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int[] pnum=new int[26];
        //统计p字符串
        for(int i=0;i<p.length();i++){
            pnum[p.charAt(i)-'a']++;
        }
        int[] snum=new int[26];
        int left=0,right=0;
        List<Integer> ans=new ArrayList<>();
        while(right<s.length()){
            //更新snum
            snum[s.charAt(right)-'a']++;
            //如果字符长度相等,进行比较
            if(right-left+1==p.length()){
                if(Arrays.equals(snum,pnum)){
                    ans.add(left);
                }
                //将left移除snum
                snum[s.charAt(left)-'a']--;
                left++;
            }  
            //往后走
            right++;
        }
        return ans;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值