242.有效的字母异位词
题目
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
提示:
1 <= s.length, t.length <= 5 * 104
s
和t
仅包含小写字母
方法
因为本题和字母相关,所以使用数组作为哈希表
遍历一遍s字符串,存入不同字符的个数
再遍历一遍t字符串,遇到的字符数组中都–
如果按照题意,则数组中所有字符都应该是0
遍历一遍如果不为0,则return false;遍历结束都符合条件,则return true;
代码
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
let res = new Array(26).fill(0);
// JS与Java语言的差异,Java中可以直接-'a'
// JS中会返回错误结果,需要使用charCodeAt()方法返回该字符的unicode值
for (let i = 0;i < s.length;i++){
res[s[i].charCodeAt() -'a'.charCodeAt()]++;
}
for (let i = 0;i < t.length;i++){
res[t[i].charCodeAt() - 'a'.charCodeAt()]--;
}
for (let i = 0;i < res.length;i++){
if (res[i] !== 0){
return false;
}
}
return true;
};
383.赎金信
题目
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = “a”, magazine = “b”
输出:false
示例 2:
输入:ransomNote = “aa”, magazine = “ab”
输出:false
示例 3:
输入:ransomNote = “aa”, magazine = “aab”
输出:true
提示:
1 <= ransomNote.length, magazine.length <= 10^5
ransomNote 和 magazine 由小写英文字母组成
方法
本题只和字母相关,所以选择数组作为哈希表
由题意可知,magazine中的各字母数量要大于等于ransomNote各字母数量
其他方法同有效的字母异位词,在最后的for循环中只需满足res数组中的各元素大于等于0即可
代码
/**
* @param {string} ransomNote
* @param {string} magazine
* @return {boolean}
*/
var canConstruct = function(ransomNote, magazine) {
let res = new Array(26).fill(0);
let base = "a".charCodeAt();
for (let i of magazine) {
res[i.charCodeAt() - base]++;
}
for (let i of ransomNote) {
res[i.charCodeAt() - base]--;
}
for (let i of res){
if (i < 0) {
return false;
}
}
return true;
};
49.字母异位词分组
题目
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:
输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]
示例 2:
输入: strs = [“”]
输出: [[“”]]
示例 3:
输入: strs = [“a”]
输出: [[“a”]]
提示:
1 <= strs.length <= 104
0 <= strs[i].length <= 100
strs[i]
仅包含小写字母
方法
自己的方法
// strs.lenth = 0 和 1时,单独处理
// 我的思路是将有效的字母异位词封装成一个函数
// 两层循环找相等(需要加入Set集合中去重)
// Set 再转化为数组,加入res数组中
// 时间和空间都很大
【很传统的方法,太绕了,还容易出现一些不知道如何排查的错误】
方法一:排序
由于互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。
作者:LeetCode-Solution
方法二:计数
(代码有点迷糊,不推荐该方法)
由于互为字母异位词的两个字符串包含的字母相同,因此两个字符串中的相同字母出现的次数一定是相同的,故可以将每个字母出现的次数使用字符串表示,作为哈希表的键。
由于字符串只包含小写字母,因此对于每个字符串,可以使用长度为 26 的数组记录每个字母出现的次数。需要注意的是,在使用数组作为哈希表的键时,不同语言的支持程度不同,因此不同语言的实现方式也不同。
代码
// 方法一 排序
var groupAnagrams = function(strs) {
const map = new Map();
for (let str of strs) {
// 将字符串转化为数组,方便使用数组的排序方法
let array = Array.from(str);
array.sort();
let key = array.toString();
// map中是否含有key,含有则还是赋值给list,没有就创建
// 这一步简单 但很重要
let list = map.get(key) ? map.get(key) : new Array();
// 因为之前的排序,符合条件的不同元素转化为相同的key
// 基于相同的key,我们把对应原来的str加入进去
list.push(str);
// 更新key对应的value
map.set(key, list);
}
// 取出各map中的值
return Array.from(map.values());
};
几个神奇的函数:
1.Array.from(element);看起来好像万物皆可转化为数组
Array.from(str) 字符串转化为数组
Array.from(set) 集合转化为数组
Array.from(map.values()):map的值集合转化为数组
详细可参考
https://blog.csdn.net/m0_53375764/article/details/124056984
2.数组转化为字符串,array.toString()
3.字母可排序:array.sort()
var groupAnagrams = function(strs) {
const map = new Object();
for (let s of strs) {
const count = new Array(26).fill(0);
for (let c of s) {
count[c.charCodeAt() - 'a'.charCodeAt()]++;
}
map[count] ? map[count].push(s) : map[count] = [s];
}
return Object.values(map);
};
438.找到字符串中所有字母异位词
题目
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s
和p
仅包含小写字母
方法
自己的方法
结合有效的字母异位词问题,使用for循环遍历一遍,暴力解法
滑动窗口:
【要掌握】
其实与数组里面的滑动窗口类似,只不过这是字符类型
根据题目要求,我们需要在字符串 ss 寻找字符串 pp 的异位词。因为字符串 pp 的异位词的长度一定与字符串 pp 的长度相同,所以我们可以在字符串 ss 中构造一个长度为与字符串 pp 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 pp 中每种字母的数量相同时,则说明当前窗口为字符串 pp 的异位词。
在算法的实现中,我们可以使用数组来存储字符串 pp 和滑动窗口中每种字母的数量。
细节
当字符串 ss 的长度小于字符串 pp 的长度时,字符串 ss 中一定不存在字符串 pp 的异位词。但是因为字符串 ss 中无法构造长度与字符串 pp 的长度相同的窗口,所以这种情况需要单独处理。
作者:LeetCode-Solution
代码
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function(s, p) {
let res = new Array();
for (let i = 0;i < s.length - p.length + 1;i++){
let temp = s.substring(i,i + p.length);
if (isAnagram(temp,p)){
res[res.length] = i;
}
}
return res;
};
var isAnagram = function(s, t) {
let res = new Array(26).fill(0);
// JS与Java语言的差异,Java中可以直接-'a'
// JS中会返回错误结果,需要使用charCodeAt()方法返回该字符的unicode值
for (let i = 0;i < s.length;i++){
res[s[i].charCodeAt() -'a'.charCodeAt()]++;
}
for (let i = 0;i < t.length;i++){
res[t[i].charCodeAt() - 'a'.charCodeAt()]--;
}
for (let i = 0;i < res.length;i++){
if (res[i] !== 0){
return false;
}
}
return true;
};
滑动窗口
var findAnagrams = function(s, p) {
const sLen = s.length, pLen = p.length;
if (sLen < pLen) {
return [];
}
const ans = [];
const sCount = new Array(26).fill(0);
const pCount = new Array(26).fill(0);
for (let i = 0; i < pLen; ++i) {
++sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++pCount[p[i].charCodeAt() - 'a'.charCodeAt()];
}
if (sCount.toString() === pCount.toString()) {
ans.push(0);
}
for (let i = 0; i < sLen - pLen; ++i) {
--sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++sCount[s[i + pLen].charCodeAt() - 'a'.charCodeAt()];
if (sCount.toString() === pCount.toString()) {
ans.push(i + 1);
}
}
return ans;
};
本道题目与最小覆盖子串比起来算是简单的
主要体现在本题的字符串都是小写字母,而最小覆盖子串字符大小写均可
最重要的是,本题求字母异位词,保证字符数量一样即可,所以可以用sCount.toString() == pCount.toString()来保证是否符合条件;而最小覆盖子串s覆盖t,说明移动到的s位置包含t的各字符,且s中该字符的数量要大于t 中该字符的数量,只能用map比较。