给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
说明: 你可以假设字符串只包含小写字母。
进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
我的算法实现:
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function (s, t) {
const sLen = s.length;
const tLen = t.length;
// 如果长度不同,肯定不是
if (sLen !== tLen) {
return false;
}
const sObj = {}, tObj = {}
// 将字符串转换成对象,由于有可能存在相同的字符,所以同时需要记下字母出现的个数
for (let i = 0; i < sLen; i ++) {
sObj[s.charAt(i)] = (sObj[s.charAt(i)] || 0) + 1;
tObj[t.charAt(i)] = (tObj[t.charAt(i)] || 0) + 1;
}
const sKeys = Object.keys(sObj)
// 然后逐一比较即可,不相等就代表不是
for (let k = 0; k < sKeys.length; k ++) {
if (sObj[sKeys[k]] !== tObj[sKeys[k]]) {
return false;
}
}
return true;
};
第一次理解错了,异位看成是移位了,导致第一次提交错误。
我的思路很简单,就是将 s 和 t 字母以及出现的个数保存为对象,然后循环对象看看彼此相不相等。
我还想到了一种方法,就是如果 s 中的字母在 t 中有,那么就删除 t 中对应的字母,直到 s 的字母全部遍历完成,如果都是相等的,那么说明是,否则就不是。这个最后得出的结果的时间很大:
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function (s, t) {
if (s.length !== t.length) {
return false;
}
const tArr = t.split('');
for (let i = 0; i < s.length; i ++) {
let index = tArr.indexOf(s.charAt(i))
if (index === -1) {
return false;
}
tArr.splice(index, 1);
}
return true;
};
光看代码比上面的要少,只不过使用了三个内部方法,可能花费时间最多的也是这个原因。
官方的讲解: 有效的字母异位词
这次官方的讲解没有吸引人的,第一种通过排序的方法还可以,只不过时间复杂度同样很大;第二个方法是利用哈希表,跟我上面那个有异曲同工之处,只不过在空间上,明显官方的更好,毕竟一直都是在一个对象上操作。
在 js 中由于可以动态添加属性,所以不用像官方那样刚开始就是 26 的英文字母,直接采用 s 在对应字母上 +1 (不管有没有,没有给个默认值 0), t 则是在对应字母上 -1 。完成后只要发现有不为 0 的,那么就返回 false。
来源:力扣(LeetCode)