滑动窗口(3, 438,76)

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

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //滑动窗口(双指针!)
        int n = s.length();
        Map<Character, Integer> map = new HashMap<>();
        if(n == 0) return 0;
        int left = 0, ans = 1;
        for(int right = 0;right < n;right++){
            char ch = s.charAt(right);
            if(map.containsKey(ch)){
               left = Math.max(map.get(ch) + 1, left);//这一步很关键!因为left更新后,map中可能有元素未更新,若不使用max,则会使left前移
            }
            map.put(ch, right);
            ans = Math.max(right-left+1, ans);
        }
        return ans;

        //动态规划 用了substring比较耗时
        // int n = s.length(), ans = 1;
        // if(n == 0) return 0;
        // int[] dp = new int[n];
        // dp[0] = 1;
        // for(int i = 1;i < n;i++){
        //     if(s.substring(i-dp[i-1], i).indexOf(s.charAt(i)) == -1){//上一个最长序列不包含该字母
        //         dp[i] = dp[i-1] + 1;
        //     }
        //     else{
        //         int loc = s.substring(i-dp[i-1], i).lastIndexOf(s.charAt(i));//lastIndexOf最后依次出现的位置
        //         dp[i] = dp[i-1] - loc;
        //     }
            
        //     ans = Math.max(ans, dp[i]);
        // }  
        // return ans;
    }
}

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

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        //滑动窗口
        List<Integer> ans = new ArrayList<>();
        if(p.length() > s.length())
            return ans;
        int len = p.length();
        //定义数组记录s,p中出现的字母频次(关键!)根据两数组是否相等来判断异位词!
        int[] sCont = new int[26];//该数组并不是记录整个s的字母,而是每次选取len个连续字母记录!
        int[] pCont = new int[26];
        for(int i = 0;i < len;i++){
            sCont[s.charAt(i)-'a']++;
            pCont[p.charAt(i)-'a']++;
        }
        if(Arrays.equals(sCont, pCont))
            ans.add(0);
        for(int i = 1;i <= s.length()-len;i++){
            sCont[s.charAt(i-1)-'a']--;
            sCont[s.charAt(i+len-1)-'a']++;
            if(Arrays.equals(sCont, pCont)){
                ans.add(i);
            }
        }
        return ans;

        //滑动窗口+双指针
        // List<Integer> ans = new ArrayList<>();
        // if(p.length() > s.length())
        //     return ans;
        // int len = p.length();

        // int[] sCont = new int[26];
        // int[] pCont = new int[26];
        // for(int i = 0;i < len;i++){
        //     pCont[p.charAt(i)-'a']++;
        // }
        // int left = 0;
        // for(int right = 0;right < s.length();right++){
        //     sCont[s.charAt(right)-'a']++;
        //     while(sCont[s.charAt(right)-'a'] > pCont[s.charAt(right)-'a']){//说明s[left--right]中有其他字母或多余字母,要将left一直左移直到去掉多余字母
        //         sCont[s.charAt(left)-'a']--;
        //         left++;
        //     }
        //     if(right-left+1 == len){
        //         ans.add(left);
        //     }
        // }
        // return ans;
    }
}

76. 最小覆盖子串

76

class Solution {
    public String minWindow(String s, String t) {
        //滑动窗口
        int sLen = s.length();
        int tLen = t.length();
        //维护两个数组,记录已有字符串指定字符的出现次数,和目标字符串指定字符的出现次数
        //ASCII表总长128
        int[] need = new int[128];
        int[] have = new int[128];
        //将目标字符串指定字符的出现次数记录
        for (int i = 0; i < t.length(); i++) {
            need[t.charAt(i)]++;
        }
        //初始化
        int left = 0, right = 0;
        int count = 0;//记录have中的need需要的字符数量
        int minl = sLen+1, begin = 0;//用于记录答案

        while(right < sLen){
            char r = s.charAt(right);
            if(need[r] == 0){//不是需要的字符
                right++;
                continue;
            }
            //一定要先判断
            if(have[r] < need[r]){//如果r为被目标字符串需要,且出现的频次小于指定频次
                count++;
            }

            have[r]++;
            right++;
            //窗口里的字符已经满足需求,移动left
            while(count == tLen){
                if(right - left < minl){//记录最小窗口
                    minl = right - left;
                    begin = left;
                }
                char l = s.charAt(left);
                if(need[l] == 0){//l不是需要的字符
                    left++;
                    continue;
                }
                //一定要先判断
                if(have[l] == need[l])//如果左边即将要去掉的字符被目标字符串需要,且出现的频次正好等于指定频次
                    count--;
                    
                have[l]--;
                left++;
            }
        }
        if(minl == sLen+1)
            return "";
        return s.substring(begin, begin+minl);
    }
        //暴力法,超时
    //     int len = t.length(), n = s.length();
    //     if(n < len)
    //         return "";
    //     Map<Character, Integer> chToNum = new HashMap<>();
    //     for(int i = 0;i < len;i++){
    //         char ch = t.charAt(i);
    //         chToNum.put(ch, chToNum.getOrDefault(ch, 0)+1);
    //     }
    //     Map<Character, Integer> map = new HashMap<>();
    //     for(int l = len;l <= n;l++){
    //         //初始化
    //         map.clear();
    //         for(int i = 0;i < l;i++){//当l>len时
    //             char ch = s.charAt(i);
    //             map.put(ch, map.getOrDefault(ch, 0)+1);
    //         }
    //         //滑动窗口
    //         for(int start = 0;start <= n-l;start++){
    //             if(start > 0){
    //                 char ch1 = s.charAt(start-1), ch2 = s.charAt(start+l-1);
    //                 map.put(ch1, map.get(ch1)-1);
    //                 map.put(ch2, map.getOrDefault(ch2, 0)+1);
    //             }
    //             if(chToNum.size() > map.size())
    //                 continue;
    //             if(f(chToNum, map))
    //                 return s.substring(start, start+l);
    //         }
    //     }
    //     return "";
    // }

    // public boolean f(Map<Character, Integer> chToNum, Map<Character, Integer> map){
    //     for(Map.Entry<Character, Integer> entry : chToNum.entrySet()){
    //         char ch = entry.getKey();
    //         int num = entry.getValue();
    //         if(!map.containsKey(ch) || map.get(ch) < num)
    //             return false;
    //     }
    //     return true;
    // }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值