【算法学习】【字符串】【是否存在变位词】

Q:给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。假设字符串全是小写字母

看到这道题,最吸引我的还是【变位词】

你给翻译翻译,什么叫变位词?

变位词,即字母位置变换但是数量不变的字符串。

其实简单来说 ,如果将字符串视为数组的话,这就是在问你s1 数组内是否存在s2数组的子集?

针对字符串类的问题,用我擅长的方式就是类比,字符串可以视为多个字母构成的数组,那么但凡是数组类的问题,我们都可以使用【双端指针】or【哈希+遍历】的方式去解决 。

回到问题上来 ,如果存在变位词,那么也是就说s1里存在的字母,在s2中也出现了。

也就是说存在了映射关系,既然有了映射关系那必然存在一张映射表进行维护。

那么假设,字母作为key,value为在字符串内出现的次数(默认0)。

我们先使用s1对映射表进行初始化,目的是统计出s1中字母出现的频率。

接下来,再使用s2字符串对映射表进行操作,当出现了同样的字母则扣减统计次数。

顺利的话,映射表内value=0的字母就是共有的字母了。

但如果不顺利的话,就需要利用【滑动窗口】的想法(窗口大小为短字符串的长度)来进行遍历匹配得到最终结果。

有一点比较特殊的是,题目限定了字符串均为小写字母,相当于给定了映射表的大小。

同时由于全部是小写字母,那么我们利用小写字母的ascii码来进行计算,因为小写字母的ascii码是递增的。

eg:当用‘a’ - ‘a’,由于同样的字母,则结果0,而0在数组中指向了首个元素;

        当用‘b’ - ‘a’,由于相邻字母ascii码递增,所以差值为1,而1在数组中指向了第2个元素,正好  是当前字母在字母表中的顺序。

综上所述,代码如下:

    public static void main(String[] args) {
        String s1 =  "ac";
        String s2 =  "dgcaf";
        System.out.println(check(s1,s2));

    }

    public static boolean check(String s1, String s2 ){
        //init初始化容器
        int[] counts = new int[26];
        for (int i = 0; i < s1.length(); ++i) {
            //这里想表达的是 利用字母的ascii码进行做差,差值即索引位置,如果存在则转换成1
            //eg:a的ascii码是97,b的ascii码是98;如果a存在则索引0的值为1,否则是0
            counts[s1.charAt(i)-'a']++;
            //这里想表达的是,如果在S2中找到了同样位置的索引,则将容器值减1,一般结果为0 or -1
            counts[s2.charAt(i)-'a']--;
        }
        if (allZero(counts)){
            return true;
        }
        //这里使用了滑动窗口的思想,窗口大小为s1的长度
        //i指定s1的长度,想表达的是指定了窗口的初始化位置
        for (int i = s1.length(); i < s2.length(); i++) {

            //界定窗口左边界右移动 dgcaf中的 'd' 已经重新补位置
            counts[s2.charAt(i-s1.length())-'a']++;

            //界定窗口右边界右移动 dgcaf中的 'c' 已经重新扣减
            counts[s2.charAt(i)-'a']--;
              
            //以上操作 完成了dgcaf中 窗口从[dg]caf -> d[gc]af的变化 (初始化窗口是[dg]是因为初始化时刻 s1的长度导致)
            //伴随着遍历,形成了窗口的滑动趋势,从s2的左端一直滑动到s2的右端
            if (allZero(counts)){
                return true;
            }
        }
        return false;
    }

    public static boolean allZero(int[] counts){
        for (int value: counts) {
            if (value!=0){
             return false;
            }
        }
        return true;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值