求子串问题,不考虑子串元素的顺序,滑动窗口法实现(Java)

文章目录

题目

给定长度为m的字符串aim,以及一个长度为n的字符串str
问能否在str中找到一个长度为m的连续子串,使得这个子串刚好由aim的m个字符组成,顺序无所谓
返回任意满足条件的一个子串的起始位置,未找到返回-1

输入:
aabbccddffaa
ddcc

输出:
4

分析

使用滑动窗口加欠债表实现
1、构建一个欠债表,将aim中的字符串放入欠债表,并记录每个元素欠的个数
2、建立窗口,窗口大小和aim大小一致,将str前面aim.length个元素和欠债表进行比对,每出现一个欠债表的元素,那么欠债表中欠的元素
的个数减一,如果欠债表中不欠该元素,那么无效元素+1
3、第二步建立完窗口后,如果此时正好无效元素为0个,那就证明不欠债了(因为窗口中的元素和aim一样多,如果窗口没有无效元素,那么就都是有效元素,有效元素个数和aim一样多,那就是正好匹配上了被,此时直接返回结果就行)如果有无效元素,那么就是还欠债,就可以开始滑动窗口了,

  • 窗口每次向后滑动一个格子,判断新进来的元素是不是在欠债表中有,有的话欠债减一,没有的话,欠的个数也会减一,原本不欠的话,欠的个数是0,那么此时会变成负数,如果变成负数那么就是无效元素,无效元素加一
  • 窗口大小不变的情况下向后滑动,那么之前窗口中最前面的一个元素必定会从窗口中出去,那么这时候欠债表中这个元素欠的个数就要加一,如果原本这个元素欠的就是负数,那么他原本就是无效元素,是无效元素的话,无效元素减一

4、在窗口每滑动一个格判断一次无效元素是不是等于0,如果等于0就返回当前窗口的起始位置就可以了
5、如果到最后也没找到,按题目要求返回-1

实现

	public static int search(String a, String b){
        char[] aArr = a.toCharArray();
        char[] bArr = b.toCharArray();
        //欠债表,ASCII码个数个数组个长度,用来记录每个元素出现次数
        int[] count = new int[256];

        for (int i = 0; i < bArr.length; i++){
            count[bArr[i]]++;//将b中的中每一个元素放入欠债表
        }
        // 记录无效点数
        Integer inValidTimes = 0;
        int n = 0;// 滑动窗口的起始位置
        for (;n < bArr.length; n++){// 构建滑动窗口
            // 如果A的前四个中添加了b没有的元素,那么视为无效元素,无效元素个数加一
            if(count[ aArr[n] ] -- == 0){
                inValidTimes++;
            }
        }
        // 从上面的循环出来后,此时n的位置为bArr.length,不需要再重新赋值了,直接跑
        for (; n < aArr.length; n++){
            if(inValidTimes == 0){//如果不欠债了,直接返回当前窗口的起始下标
                return n - bArr.length + 1;
            }
            // 如果当前元素在欠债表中有,欠的债加一
            if(count[ aArr[n] ] -- == 0){
                inValidTimes++;
            }
            // 如果窗口前面弹出的元素在欠债表中多给了,欠债表中的元素减一
            if(count[ aArr[n-bArr.length] ] ++ < 0){
                inValidTimes--;
            }
        }
        // 最后一个窗口没有判断是否匹配就从循环走出来了,所以这里需要再判断一下
        return inValidTimes == 0 ? n - bArr.length + 1 : -1;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值