383. 赎金信 JavaScript实现

80 阅读2分钟

383. 赎金信

  • 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
  • 如果可以,返回 true ;否则返回 false 。
  • magazine 中的每个字符只能在 ransomNote 中使用一次。

一、原来的想法

  • 把magazine字符串中的分割成字符数组,存到哈希表中。

  • 然后遍历ransomNote中的每个字符,检查哈希表中是否存在。存在就把它删除(防止有多个相同的数字),如果不存在就false.

  • 问题在于:magazine存在相同的值,但是magazine 中的每个字符只能在 ransomNote 中使用一次。所以不能用set.

  • 如果用map,那么存哈希表的时候,如果是值作为key,由于key的唯一性,会去掉重复的元素。 如果是值作为value,那么在检查哈希表中是否有值的时候,还要靠考虑这个值的索引,才能通过get()方法得到对应的值,而索引是未知的。

  • 所以最后使用数组实现了,但是有点慢。

var canConstruct = function(ransomNote, magazine) {
    // 1、将ransomNote存到哈希表中
    let help = []
    // 转换字符数组形式
    let m = magazine.split('')
    for(let i=0; i<m.length; i++){
        help.push(m[i])
    }

    // 2、检查magazine里的每个字符在哈希表中是否存在
    for(let s of ransomNote.split('')){
        if(help.indexOf(s) != -1){
            // 存在,就把这个元素从哈希表中剔除
            help.splice(help.indexOf(s),1)
        }else{
            return false
        }
    }
    return true
};

二、官方题解

题目思想和[有效的字母异位词](https://juejin.cn/post/7138698862029930532)类似,因为都是针对26个字母,所以可以维护一个26字母长的数组,把索引当作元素的值,值当作元素的数量

image.png

var canConstruct = function(ransomNote, magazine) {
    // 比较长度
    if(magazine.length < ransomNote.length) return false

    // 将magazine里的字母和数量进行存储
    const cnt = new Array(26).fill(0)
    for(const m of magazine){
        // 由于组成的都是小写字母,所以每个字母对应一个索引下标,值就是数量
        cnt[m.charCodeAt() - 'a'.charCodeAt()]++
    }

    // 遍历ransomNote里的值,将哈希表中的数量--
    for(const r of ransomNote){
        cnt[r.charCodeAt() - 'a'.charCodeAt()]--
        // 如果减去之后小于0,证明哈希表中没有这个字母
        if(cnt[r.charCodeAt() - 'a'.charCodeAt()] < 0){
            return false
        }
    }
    return true
};