题目:
Given two strings s and t , write a function to determine if t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram" Output: true
Example 2:
Input: s = "rat", t = "car" Output: false
Note:
You may assume the string contains only lowercase alphabets.
Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case?
这道题是求两个给定的字符串是不是anagram,anagram的定义就是两个字符串由完全相同的字母和个数组成。
看到这道题第一个想到的办法就是分别对s和t计算每个字母出现了多少次,可以采用unordered_map存储,然后比较两个unordered_map是否相同。这种写法的时间复杂度是O(n),空间复杂度也是O(n),但是存储了两个unordered_map。运行时间16ms,55.27%,空间9.4M,88.06%:
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char, int> chars_s;
for (int i = 0; i < s.size(); i++) {
if (chars_s.count(s[i]) == 0) {
chars_s[s[i]] = 1;
}
else {
chars_s[s[i]]++;
}
}
unordered_map<char, int> chars_t;
for (int i = 0; i < t.size(); i++) {
if (chars_t.count(t[i]) == 0) {
chars_t[t[i]] = 1;
}
else {
chars_t[t[i]]++;
}
}
return chars_s == chars_t;
}
};
2022.11.9 果然还是先想到了这个最简单粗暴的方法
class Solution {
public boolean isAnagram(String s, String t) {
return countChar(s).equals(countChar(t));
}
private Map<Character, Integer> countChar(String s) {
Map<Character, Integer> map = new HashMap<>();
for (char c : s.toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
return map;
}
}
后来看了discussion才意识到还可以直接使用一个unordered_map解决。自己想到的办法是,先对s进行一次遍历存入unordered_map,然后在遍历t的时候,在对应的key-value pair里面把value--。刚开始写的时候没有考虑到两个字符串长度不同,可能会出现t中的value都减完了但是s中还有多的(比如"ab", "a"的情况,多了个b),所以需要在前面提前判断字符串的长度,如果不同的话直接返回0。这种方法其实不是个好方法,运行时间28ms,21.81%,空间9.4M,88.06%:
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size()) {
return false;
}
unordered_map<char, int> chars_s;
for (int i = 0; i < s.size(); i++) {
if (chars_s.count(s[i]) == 0) {
chars_s[s[i]] = 1;
}
else {
chars_s[s[i]]++;
}
}
for (int i = 0; i < t.size(); i++) {
if (chars_s[t[i]] != 0) {
chars_s[t[i]]--;
}
else {
return false;
}
}
return true;
}
};
2022.11.9 这个方法我现在不知道意义何在,直接拿数组不香么。
还有一种做法只需要进行一次遍历,就是在每次遍历的过程中,对s中出现的字符的个数++,对t中出现的字符的个数--。刚开始觉得要先初始化为0好像很麻烦,但发现其实可以不用初始化,猜测原因是unordered_map<char, int>在初始化一个char对应的value时自动填0,于是就能直接++和--,非常方便。这种情况下时间复杂度也要小一倍。时间12ms,81.09%,空间9.4M,86.57%:
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size()) {
return false;
}
unordered_map<char, int> chars;
for (int i = 0; i < s.size(); i++) {
chars[s[i]]++;
chars[t[i]]--;
}
for (unordered_map<char, int>::iterator it = chars.begin(); it != chars.end(); it++) {
if (it->second != 0) {
return false;
}
}
return true;
}
};
2022.11.9 同理,这个方法我现在不知道意义何在,直接拿数组不香么。
上面这种做法还可以简化为直接用数组,相当于把hash_map的key当作数组的下标,顺序地将0-25赋给a-z,听说可以加快运行速度。12ms,81.09%,9.6M,55.22%:
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size()) {
return false;
}
char chars[26] = {0};
for (int i = 0; i < s.size(); i++) {
chars[s[i] - 'a']++;
chars[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (chars[i] != 0) {
return false;
}
}
return true;
}
};
2022.11.9
了解思路以后秒写出来了。
class Solution {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
int[] array = new int[26];
for (int i = 0; i < s.length(); i++) {
char sc = s.charAt(i);
char tc = t.charAt(i);
array[sc - 'a']++;
array[tc - 'a']--;
}
for (int i : array) {
if (i != 0) {
return false;
}
}
return true;
}
}
最后还有一种做法就是万能的sort,因为anagram所有包含的字母个数都一样,所以sort完的字符串一定是一样的。时间复杂度为sort的O(nlogn),空间复杂度也根据sort算法来看。运行时间36ms,6.94%(不忍直视),空间0.5M,79.1%:
class Solution {
public:
bool isAnagram(string s, string t) {
sort(s.begin(), s.end());
sort(t.begin(), t.end());
return s == t;
}
};
2022.11.9
代码也很简单,得先toCharArray以后再Arrays.sort(),然后Arrays.equals()
class Solution {
public boolean isAnagram(String s, String t) {
char[] sChar = s.toCharArray();
char[] tChar = t.toCharArray();
Arrays.sort(sChar);
Arrays.sort(tChar);
return Arrays.equals(sChar, tChar);
}
}