题目
🔗题目链接:383. 赎金信 - 力扣(LeetCode)
给你两个字符串: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 <= 105
ransomNote
和magazine
由小写英文字母组成
思路
解题思路参考242. 有效的字母异位词
但需要注意的是,需要先遍历 magazine ,在遍历 magazin 时对数组元素进行加一操作;然后在遍历 ransomNote 时对数组元素进行减一操作。最后只要数组中元素均大于等于 0 即为成功。
若在遍历 ransomNote 时对数组元素进行加一操作,在遍历 magazin 时对数组进行减一操作,然后依据数组元素是否均大于等于 0 来判断。得到的答案是错误的。可以将 ransomNote = "aa", magazine = "aab" 带入进行测试。当 ransomNote = "aa", magazine = "aab" 时,即使 magazine 满足条件,数组中会存在小于 0 的元素。
代码
function canConstruct(ransomNote: string, magazine: string): boolean {
// 分别计算两个字符串的长度
const ransomNoteLens = ransomNote.length;
const magazineLens = magazine.length;
// 如果长度不同,直接返回 false
if (ransomNoteLens > magazineLens) return false;
// 创建一个长度为26的数组,且每个元素赋值为0
const assicArr = new Array(26).fill(0);
// 获取字符a的ASCII码
// 因为英文小写a~z的ASCII码并不是从0-26的
// 所以将要遍历的字符串中的字符的ASCII码都要减去 a 的ASCII码
// 这样就可以从将这些英文字符从0开始编码,符合我们创建的数组
const baseCode = "a".charCodeAt(0);
// 将对应元素加一
// 注意,这里要先遍历 magazine 中的字符
// 因为 magazine 长度是大于 ransomNote
for (let i = 0; i < magazineLens; i++) {
// 获取字符在数组中的位置
const gap = magazine.charCodeAt(i) - baseCode;
// 将对应为位置的元素加一
assicArr[gap]++;
}
// 将对应元素减一
// 当遍历 ransomNote 的时候,对数组元素进行减一操作
for (let j = 0; j < ransomNoteLens; j++) {
// 获取字符在数组中的位置
const gap = ransomNote.charCodeAt(j) - baseCode;
// // 将对应为位置的元素减一
assicArr[gap]--;
// 遍历 ransomNote 字符时,若发现有小于0的
// 说明 magazine 中一定不包含 ransomNote 中所需字符
if (assicArr[gap] < 0) return false;
}
return true;
};
-
时间复杂度: O(n)
遍历了 m + n 次,其中 n <= ransomNoteLens。
-
空间复杂度: O(1)