当前位置: 代码迷 >> 综合 >> js + leetcode刷题:No.1160 拼写单词
  详细解决方案

js + leetcode刷题:No.1160 拼写单词

热度:59   发布时间:2023-09-22 02:35:13.0

题目:

给你一份『词汇表』(字符串数组) 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 = truefor(let item of w){if(item in eachObj && eachObj[item] > 0){eachObj[item] -= 1}else{isOk = falsebreak}}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换成标注个元素个数的mapfor(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 = charslet 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给出一个新数组,也是一种方式