剑指offer14:字符串中的变位词

题目:
输入字符串s1和s2,如何判断字符串s2中是否包含字符串s1的某个变位词(组成各个单词的字母以及每个字母出现的次数完全相同,只是字母的排列的顺序不同例如pots和stop)?如果字符串s2中包含字符串s1的某个变位词,则字符串s1至少有一个变位词是s2的子字符串。假设两个字符串中只包含英文小写字母。例如,字符串s1为“ac”,字符串s2为“dgcaf”,由于字符串s2中包含字符串s1的变位词“ca”,因此输出为true。如果字符串s1为“ab”,字符串s2为“dgcaf”,则输出为false。
回顾:
刚刚到新的章节字符串,来回顾一下String类型常用的函数,charAt函数返回指定下标字符,compareTo按照字典顺序比较字符串,equals判断两个字符串的长度和内容是否相同,indexOf返回字符串中某个字符或子字符串首次出现的下标位置,lastIndexOf返回字符串中某个字符或子字符串最后出现的下标位置,length返回字符串长度,split按字符串指定的分隔符进行分割,substring根据下标截取字符串,toLowerCase/toUpperCase将字符串中的所有大写或小写字母改造成小写或大写字母。
分析:
变位词的特点是长度必须一定相同,其次组成变位词的字母集合一定相同,并且每个字母出现的次数也相同。
暴力法可以解决,求出s1字符串的所有排列,然后判断每个排列是不是字符串s2的子字符串,如果一个字符串有n个字符,那么它一个有n!个排列,因此时间复杂度不会低于O(n!),时间复杂度太高不可取。
可以采用哈希表统计字符串包含的字母以及每个字母出现的次数,具体操作如下图例子所示。
解决这种问题的思路就是利用好数组,完全可以利用两个ASCII值相减得到数组下标,数组下标对应的就是那26个字母,然后通过规律添加元素字母对应的次数值减1,减少元素字母对应的次数值加1,如存在数组所有值都等于0的时,说明存在变位词。
在这里插入图片描述

代码如下:

public class CheckInclusion {
    public static void main(String[] args) {
        String s1 = "ca";
        String s2 = "dgacf";
        boolean b = checkInclusion(s1, s2);
        System.out.println(b);

    }
    public static boolean checkInclusion(String s1,String s2){
        if (s1.length()>s2.length()){
            return false;
        }
        int[] counts = new int[26];
        for (int i = 0; i < s1.length(); i++) {
            counts[s1.charAt(i)-'a']++;
            counts[s2.charAt(i)-'a']--;
        }
        if (allAllZero(counts)){
            return true;
        }
        for (int i = s1.length(); i <s2.length() ; i++) {
            counts[s2.charAt(i)-'a']--;
            counts[s2.charAt(i-s1.length())-'a']++;
            if (allAllZero(counts)){
                return true;
            }
        }
        return false;
    }

    private static boolean allAllZero(int[] counts) {
        for (int count : counts) {
            if (count !=0){
                return false;
            }
        }
        return true;
    }
}

在这里插入图片描述
该算法利用了两个for循环,扫描字符串s1和s2各一次,如果两者长度分别是m和n,那么算法时间复杂度O(m
+n),空间复杂度由于建立的是固定常数大小的数组,所以空间复杂度为O(1)。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙崎流河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值