【哈希表第一篇】第242题. 有效的字母异位词

176 阅读3分钟

哈希和数组、链表不同,如果从题目中看出非用哈希处理不可,这是很重要的
第一,包含键值对,如果题目中包含显示或隐式键值对,一定要用哈希
第二,

第242题. 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

「说明:」你可以假设字符串只包含小写字母。

遇到这种字符串,第一反应就是想到将String转变为char数组
char[] charArray1=string1.toCharArray(); 变成一个个的char之后,还可以与int比较,做加减运算

思路
先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。

暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。

「数组其实就是一个简单哈希表」,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。

需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。

为了方便举例,判断一下字符串s= “aee”, t = “eae”。

操作动画如下:

图片

定义一个数组叫做record用来上记录字符串s里字符出现的次数。

需要把字符映射到数组也就是哈希表的索引下表上,「因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下表0,相应的字符z映射为下表25。」

再遍历字符串s的时候,「只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。」 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

那么最后检查一下,「record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。」

最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。

class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length()!=t.length()) return false; // 长度不同,一定不是,特殊情况优先处理
      int[] record=new int[26];  // 这个数组的值用于记录次数
      char[] charArray1=s.toCharArray();  // 变成字符数组
      char[] charArray2=t.toCharArray();
      
      for (int i=0;i<s.length();i++){   //  遍历s字符串,
          record[charArray1[i]-'a']++;
      }
      for (int i=0;i<t.length();i++){
          record[charArray2[i]-'a']--;
      }
      for (int i=0;i<record.length;i++){  // 遍历整个record数组
         if(record[i]!=0)  
            return false; //有一个不为0,就不同 
      }
      // record数组所有元素都为零0,说明字符串s和t是字母异位词
      return true;
    }
}

这里用到涉及字符串题目的三个基本操作
第一,char[] charArray1=s.toCharArray(); 将输入的字符串变为字符数组;
第二,record[charArray1[i]-‘a’] 变为字符数组的各个值,可以与常字符加减运算,得到的数组作为record数组的下标
第三,既然record数组的下标为字符,其值表示什么呢?表示这个字符的出现次数。
还有一个计数思想,一加一减,看是否为0,作为字母异位符的充要条件(将业务意义用代码表示出来是很重要的,需要时充要表示,像解答数学题目一样,如动态规划,从业务意义中抽取出dp特征方程就是这样)

Java里面,遍历要用到长度:
数组对象.length
String对象.length()
集合框架(list set map).size()