滑动窗口:转山转水转佛陀,只为途中与你相见

1.问题描述:

给定一个字符串S和非空字符串P,在S中找出所有P的变位词的起始索引,例如:

输入:

s: "cbaebabacd" p: "abc" 

输出:

[0, 6]

2.问题分析:

从问题的描述可以看出所谓的变位词只是顺序可以改变,其他的一切不能改变,我首先想到的是从S中逐一取出字符然后在P进行匹配,匹配长度为P.length(),但是这样存在一个为题——S中连续重复出现P中的字母例如:输入:s: "cbaababaca" p: "abc" ,输出:[0,1,2,3,4,5,6,7],显然这些起始并非都是P的变位词,出现这种问题的原因在于重复使用了P中的某个字符,对症下药——对P中的字符进行标记,从而避免对P中字符重复匹配而产生的上述问题。我们可以用map对P中的每个字母进行标记,这里我们使用数组作为标记,同时介绍一种“滑动窗口”的思想。

3.窗临汴河水,门渡楚门人

public List<Integer> findAnagrams(String s, String p) {
        List<Integer> results = new ArrayList<Integer>();
        
        if(s==null || s.length() < p.length()) return results;
        
        char[] cp = p.toCharArray();
        int[] hash = new int[256];
        for(char c : cp) hash[c]++;
        
        int left = 0, right = 0, counter = 0;
        while(right < s.length()){
            if(hash[s.charAt(right++)]-- >= 1)counter++;
            if(counter==p.length()) results.add(left);
            if(right-left == p.length() && hash[s.charAt(left++)]++ >= 0)counter--;
        }
        return results;
    }
注释:用hash数组对P中的字符进行标记,核心逻辑于while中的三个if中:1.根据hash数组的标记进行计数;2.匹配完成,记录结果;3.撑开窗口,进行移动。

4.由此及彼,见异思迁

给定一个字符串S和字符串T,在S中找出包含T的最短字符串,例如:S = "ADOBECODEBANC"   T = "ABC"     result = "BANC"。

public String minWindow(String s, String t) {
        String results = new String();
        if(s==null || t==null || t.length() == 0 || s.length() < t.length()) return results;
        
        char[] ct = t.toCharArray();
        int[] hash = new int[256];
        for(char c : ct){
            hash[c]++;
        }
        //open window
        int left = 0, right = 0, begin = 0, range = s.length()+1, counter=0;
        while(right < s.length()){
            if(hash[s.charAt(right++)]-- >=1)counter++ ;
        
            while(counter==t.length()){
                if(range > right-left){
                    range = right - (begin=left);
                    results = s.substring(begin,begin+range);
                }
                
                if(hash[s.charAt(left++)]++ >=0 )counter--;
            }
              
        }
        return results;
    }
注释:核心代码同样是位于while中,不同的是其中嵌套了一个while,内部这个while的目的是缩小窗口+移动窗口,巧妙之处在 if 判断之处对窗口进行了缩小,用 if 主体代码跳出循环移动窗口!

5.窗口体会:

left和right撑开窗口,counter记录窗口风景,left自增——窗口(缩小)移动扫描目标字符串,同时hash数组记录预定字符串中每一个字符的状态是解决问题的另一个关键点!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值