3.31---滑动窗口与子串

一、无重复字符的最长子串

主体思路是采用滑动窗口法,也就是如果窗内不包含扫描到的某元素,那就把该元素加进窗内,并且长度加一,继续下一个元素的扫描判断,但如果窗内包含该元素,那就将窗内该元素删掉,(但只是删掉,index没变,所以下一轮扫描还是该元素)然后在下一轮while里面再加进来(相当于更新了一下重复元素的位置) 

class Solution {
    public int lengthOfLongestSubstring(String s) {
          ArrayList<Character> window = new ArrayList<>();
        int lens = s.length();
        int max = 0,index = 0;
       while(index < lens){
           if(!window.contains(s.charAt(index))){
               window.add(s.charAt(index));
               index++;
               max = Math.max(max,window.size());
           }else{
               window.remove(0);
           }
        }
        return max;
    }
}

一些小想法:如果要输出最长字串,可以在max赋值前判断这时的窗长window.size是不是max,如果是,新定义一个list用来存储窗里的数据,最后,输出这个list。

二、找到字符串中所有字母异位词

主题思路也是用一个滑动窗口,窗长为p的长度,然后依次向s的末尾滑动

 public static List<Integer> findAnagrams(String s, String p) {
        List<Integer> list = new ArrayList<>();
        int index = 0,cnt = s.length();
        while(index <= cnt-p.length()){
            String sub = s.substring(index,index+p.length());
            if(isAnagram(p,sub)){
                list.add(index);
            }
            index++;
        }
        return list;
    }
    public static boolean isAnagram(String s, String t) {
        int [] res  = new int[26];
        for(int i =0; i<s.length(); i++){
            res[s.charAt(i)-'a']++;
        }
        for(int i =0; i<t.length(); i++){
            res[t.charAt(i)-'a']--;
        }
        for(int i =0; i<res.length; i++){
            if(res[i]!=0){
                return false;
            }
        }
        return true;
    }

 三、和为K的子数组

一开始的思路使用滑动窗口,判断条件是sum和目标k的大小 ,但是我发现滑动窗口仅限于整数,一旦涉及负数例如[-1,-1,1]这样的形式就会结果出现问题,在评论区看到要用前缀和的方法。

前缀和顾名思义也就是新建立一个数组,该数组的索引i代表前i个数字的和,也就是sum[i] = sum[i-1] + num[i-1] 。

回到本题,要求和为k的子数组,也就是满足sum[j] =  sum[i] +  k,那么为了方便思路(取大的然后往数组左边方向减),将该式写成sum[i] = sum[j] - k ;该式的含义是,当索引到i,这时前i个数据和为sum[i],而它与前j个数据和为sum[j]刚好差k的大小,也就意味着i和j之间的数据就是我们需要的子数组。但是题目要求要返回子数组的个数,所以再采用一个map集合,键存储sum[i],值存储它出现的次数。我一开始写的核心处理部分如下:

 if(map.containsKey(sum - k)){
                cnt = map.get(sum - k)+1;
                map.put(sum - k, cnt);
            }
            map.put(sum, map.getOrDefault(sum, 0) + 1);

但是在处理类似于[1,2,1,2,1] 就会出现问题。发现问题在于:比如第一轮sum-k=0,然后满足if条件,于是cnt = value(0) +1;然后把cnt传给value(0)。(括号里面代表键值)下一轮sum-k=1,然后满足if条件,于是cnt = value(1) +1;然后把cnt传给value(1)。所以我们可以看到两轮都满足条件,但是第一轮cnt给的是value(0),第二轮cnt取的是的是value(1)加一,所以上一轮的结果没有给到下一轮,就出现了逻辑误区,代码重新更改为:

class Solution {
    public int subarraySum(int[] nums, int k) {
      Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);
        int sum = 0,cnt = 0;
        for(int j = 0; j < nums.length; j++ ) {
            sum += nums[j];
            if(map.containsKey(sum - k)){
                cnt += map.get(sum - k);
            }
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }
        return cnt;    
    }
}

以上来自于力扣及评论区

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值