天天看點

js + leetcode刷題:No.1160 拼寫單詞題目:解法:

題目:

給你一份『詞彙表』(字元串數組) words 和一張『字母表』(字元串) chars。

假如你可以用 chars 中的『字母』(字元)拼寫出 words 中的某個『單詞』(字元串),那麼我們就認為你掌握了這個單詞。

注意:每次拼寫時,chars 中的每個字母都隻能用一次。傳回詞彙表 words 中你掌握的所有單詞的 長度之和。

解法:

滿足條件,則說明word的字元個數小于等于chars的長度

// Solution One -- Obj
// 此處obj對象,更改就是在原對象上進行更改,是以要進行深拷貝出一個新對象
/**
 * @param {string[]} words
 * @param {string} chars
 * @return {number}
 */
let countCharacters3 = function(words, chars) {
    let resLen = 0, obj = {},eachObj = {}
    // 将chars的字元個數進行統計
    for(let c of chars){
        if(c in obj){
            obj[c] += 1
        }else{
            obj[c] = 1
        }
    }
    // 檢查每個Word的字元個數是否小于等于chars對應
    for(let w of words){
        eachObj = JSON.parse(JSON.stringify(obj));
        let isOk = true
        for(let item of w){
            if(item in eachObj && eachObj[item] > 0){
                eachObj[item] -= 1
            }else{
                isOk = false
                break
            }
        }
        if(isOk){
            resLen += w.length
        }
    }
    
    return resLen
};

// Solution Two -- Map
// es6提供了一個map結構,可以很友善設定多種類型為鍵值
/**
 * @param {string[]} words
 * @param {string} chars
 * @return {number}
 */
let countCharacters2 = function(words, chars) {
    let map = new Map(), resLen = 0
    // 将chars換成标注個元素個數的map
    for(let c of chars){
        map.set(c, map.has(c) ? map.get(c) + 1 : 1)
    }
    // 查驗words每個元素的各字元長度是否均小于等于chars對應字元
    for(let w of words){
        if(checkWordsInChars(w, new Map(map))){
            resLen += w.length
        }
    }
    return resLen
};

let checkWordsInChars = function(w, map){
    for(let c of w){
        if(map.has(c) && map.get(c) > 0){
            map.set(c, map.get(c) - 1)
        }else{
            return false
        }
    }
    return true
}

// Solution Three -- After finding and replacing the same character with space string in the chars, check the word length
/**
 * @param {string[]} words
 * @param {string} chars
 * @return {number}
 */
let countCharacters1 = function(words, chars) {
    let resLen = 0,copyChars = '';
    words.forEach(item => {
        copyChars = chars
        let eachItem = item.split('')
        while(eachItem.length > 0){
            if(copyChars.includes(eachItem[0])){
                copyChars = copyChars.replace(eachItem[0], '')
                eachItem.shift()      
            }else{
                break;
            }
        }
        if(eachItem.length === 0){
            resLen += item.length
        }
    })
    return resLen
};
           

備注:

(以下資料來源于網絡:https://segmentfault.com/a/1190000016036099;https://segmentfault.com/a/1190000014107100)

補充一下深拷貝、淺拷貝

深拷貝和淺拷貝的出現,主要是複制不同類型變量産生的:

js的基本類型: undefined、null、boolean、number、string, 按值存放在棧記憶體中的簡單資料段, 可以直接通路.

js的引用類型: 存放在堆記憶體中的對象, 變量儲存的是一個指向存放資料位置的指針. 通路引用類型(object, array)的值時, 首先從棧中擷取到存放該資料位置的指針, 然後再從堆中取得資料.

淺拷貝: 淺拷貝是拷貝引用, 拷貝後的引用都是指向同一個存放資料位置的指針, 無論操作哪一個都是在操作指向在堆中的那一個資料, 是以雙方都會有影響.

深拷貝: 在堆中重新配置設定記憶體, 将源對象的各個屬性複制進去. 對拷貝對象和源對象各自操作互不影響.

1、對象的拷貝

對象的淺拷貝:

淺拷貝是對象共用一個記憶體位址,對象的變化互相影響。比如常見的指派引用就是淺拷貝

對象的深拷貝:

簡單了解深拷貝是将對象放到一個新的記憶體中,兩個對象的改變不會互相影響。

Object.assign() 方法用于将所有可枚舉的屬性的值從一個或多個源對象複制到目标對象。它将傳回目标對象。

對于Object.assign()而言, 如果對象的屬性值為簡單類型(string, number),通過Object.assign({},srcObj);得到的新對象為‘深拷貝’;

如果屬性值為對象或其它引用類型,那對于這個對象而言其實是淺拷貝的。這是Object.assign()特别值得注意的地方。

Object.assign({}, src1, src2); 對于scr1和src2之間相同的屬性是直接覆寫的,如果屬性值為對象,是不會對對象之間的屬性進行合并的。

JSON.parse() 和 JSON.stringify()算是對 深拷貝的一個無腦實作

JSON.parse()和JSON.stringify()能正确處理的對象隻有Number、String、Array等能夠被json表示的資料結構,是以函數這種不能被json表示的類型将不能被正确處理。

2、數組的拷貝

數組的深拷貝方法要相對簡單一些可以了解為數組方法中那些會改變原數組的方法,比如:

concat

slice

es6 的Array.from

循環的map給出一個新數組,也是一種方式