這是我參與更文挑戰的第20天,活動詳情查看:更文挑戰前端
在前端突飛猛進的大背景下, ES6
也基本已經覆蓋性地全民普及。而數據結構集合和字典,也被運用於 ES6
的語法當中。 ES6
經過使用 Set
和 Map
這兩個函數,來實現集合和字典的思想。而集合和字典,又是怎麼被靈活應用的呢?面試
下面的這篇文章中,將帶領你們來一塊兒瞭解集合和字典在前端中應用,並使用 Map
和 Set
來實現前端的一些常見場景。一塊兒來學習吧~🙋♀️數組
ES6
中有集合,名爲 Set
;ES6 中的 Set 能夠作什麼呢?markdown
Set
對象: new
、 add
、 delete
、 has
、 size
Set
:多種迭代方法、 Set
與 Array
互轉、求並集/交集/差集咱們能夠建立一個函數,來返回包含 setA
和 setB
中全部元素的新集合。迭代這兩個集合,並把全部元素都添加到並集的集合中。以下代碼所示:數據結構
//模擬並集運算
const union = (setAe, setB) => {
const unionab = new Set()
setA.forEach(value => unionab.add(value))
setB.forEach(value => unionab.add(value))
return [...unionab]
}
console.log(union([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[1, 2, 5, 8,9, 4, 10]
複製代碼
模擬交集運算須要建立一個輔助函數,來生成包含 setA
和 setB
兩個集合中共同擁有元素的新集合。具體代碼以下:函數
// 模擬交集運算
const intersection = (setA, setB) => {
const intersectionSet = new Set()
const arrSetB = new Set(setB)
setA.forEach(value => {
if (arrSetB.has(value)) {
intersectionSet.add(value)
}
})
return [...intersectionSet]
}
console.log(intersection([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[5,8,9]
複製代碼
差集運算是建立集合 setA
有,而集合 setB
沒有的元素。簡單來講,就是 setA
減去和 setB
相交的部分,剩餘的部分便是差集的部分。oop
// 模擬差集運算
const difference = (setA, setB) => {
const differenceSet = new Set()
const arrSetB = new Set(setB)
setA.forEach(value => {
if (!arrSetB.has(value)) {
differenceSet.add(value)
}
})
return [...differenceSet]
}
console.log(difference([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[1, 2]
複製代碼
上面咱們實現了用Set來模擬並集、交集和差集,但這彷佛有一點點冗餘,若是遇到數據量大的時候還每一次都要執行這麼多行代碼,彷佛這樣子聽起來就那麼友好了。post
所以,咱們引入了一種新的方法來解決,ES6的擴展運算符。學習
若是使用擴展運算符來進行運算的話,整個過程只須要三個步驟:ui
接下來咱們就用擴展運算符,來一一實現並集、交集和差集。
來看下面一段代碼:
// 模擬並集運算
const union = (setA, setB) => {
return new Set([...setA, ...setB]);
}
console.log(union([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[1, 2, 5, 8,9, 4, 10]
複製代碼
經過以上代碼咱們能夠看到,使用擴展運算符,只須要短短一行代碼,便可實現具體的並集運算,這樣看起來簡潔了許多。
接下來咱們繼續用這種方法,來實現交集和差集。
// 模擬交集運算
const intersection = (setA, setB) => {
const arrB = new Set(setB);
return [...new Set([...setA].filter(x => arrB.has(x)))]
}
console.log(intersection([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[5, 8, 9]
複製代碼
與並集同樣的效果,運用擴展運算符,很簡潔的就實現了交集的功能。
// 模擬差集運算
const difference = (setA, setB) => {
const arrB = new Set(setB)
return [...new Set([...setA].filter(x => !arrB.has(x)))]
}
console.log(difference([1, 2, 5, 8, 9], [4, 5, 8, 9, 10])) //[1, 2]
複製代碼
一樣地,使用擴展運算符的方法,但與交集相反的是,交集是篩選出集合setB擁有的元素,而差集是篩選出集合setB沒有的元素,從而最終達到具體效果。
1)題意
給定兩個數組,編寫一個函數來計算它們的交集。
輸入輸出示例:
nums1
和 nums2
兩個數組的相交部分爲 [9, 4] 。2)解題思路
3)解題步驟
nums1
去重。nums1
,篩選出 nums2
中也包含的值。4)代碼實現
/** * @param {Array} nums1 數組1 * @param {Array} nums2 數組2 * @returns */
let intersection = function(nums1, nums2){
// 先進行數組去重
const arr1 = new Set(nums1);
const arr2 = new Set(nums2);
// 過濾掉arr1在arr2中已經有的元素,過濾結果即爲交集
// has可改成includes
const arr3 = [...arr1].filter(item => arr2.has(item));
return arr3;
}
console.log(intersection([1,2,3,4],[4,6,8]))
複製代碼
ES6中的Map能夠作什麼呢?
Map
對象: new
、 set
、 delete
、 clear
;下面展現一段代碼,來展現 map
的相關 API
。
const map = new Map()
//增
map.set('monday', '星期一')
map.set('Tuesday', '星期二')
map.set('Wednesday', '星期三')
console.log(map.has('monday')) //true
console.log(map.size) //3
console.log(map.keys()) //輸出{'monday', 'Tuesday', 'Wednesday'}
console.log(map.values()) //輸出{'星期一', '星期二', '星期三'}
console.log(map.get('monday')) //星期一
//刪
map.delete('monday')
//清空
map.clear()
//改
map.set('monday', '星期四')
複製代碼
1)題意
給定兩個數組,編寫一個函數來計算它們的交集。
輸入輸出示例:
nums1
和 nums2
兩個數組的相交部分爲 [9, 4] 。2)解題思路
nums1
和 nums2
都有的值。nums1
裏有的值。nums2
,找出 nums1
裏也有的值。3)解題步驟
nums1
,填充字典。nums2
,遇到字典裏的值就選出,並從字典中刪除。4)代碼實現
/** * @param {Array} nums1 數組1 * @param {Array} nums2 數組2 * @returns */
let intersection = function(nums1, nums2){
// 先創建一個字典
const map = new Map();
// 遍歷nums1的每個,並放入數組中
nums1.forEach(n => {
map.set(n, true);
});
const res = [];
// 遍歷nums2中的每個
nums2.forEach(n => {
// 與nums1中的對比,若是同樣則push進res
if(map.get(n)){
res.push(n);
map.delete(n);
}
});
return res;
}
console.log(intersection([1, 2, 2, 1], [2, 2]))
複製代碼
1)題意
給定一個只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判斷字符串是否有效。
輸入輸出示例:
2)解題步驟
nums1
,篩選出 nums2
中也包含的值。3)代碼實現
/** * * @param {String} s 括號字符串 * @returns boolean */
let isValid = function(s){
if(s.length % 2 === 1){
return false;
}
const stack = [];
const map = new Map();
map.set('(', ')');
map.set('{', '}');
map.set('[', ']');
for(let i = 0; i < s.length; i++){
const c = s[i];
if(map.has(c)){
stack.push(c);
}else{
// 獲取棧中最後一個括號的值
const t = stack[stack.length - 1];
if(map.get(t) === c){
stack.pop();
}else{
return false;
}
}
}
return stack.length === 0;
}
console.log(isValid('[]')) //true
console.log(isValid('(]')) //false
console.log(isValid('([)]')) //false
複製代碼
1)題意
給定一個整數數組 nums
和一個整數目標值 target
,請你在該數組中找出 和爲目標值 target
的那兩個整數,並返回它們的數組下標。
你能夠假設每種輸入只會對應一個答案。可是,數組中同一個元素在答案裏不能重複出現。
你能夠按任意順序返回答案。
輸入輸出示例:
nums[0] + nums[1] == 9
,返回 [0, 1]
。2)解題思路
nums
想象成相親者;target
想象成匹配條件;3)解題步驟
nums
的值,逐個來介紹所找的對象,沒有合適的就先登記,有合適的就牽手成功;key
表明此對象的值,值 value
表明對象的聯繫方式,即下標。4)代碼實現
/** * * @param {Array} nums 數組 * @param {Number} target 目標和 * @returns [] */
let twoSum = function(nums, target){
const map = new Map();
for(i = 0; i < nums.length; i++){
// 來找對象的人的值
const n = nums[i];
// 想找的目標對象的值
const n2 = target - n;
// 找到對象時
if(map.has(n2)){
return [map.get(n2), i];
}
// 找不到對象時,放進字典裏等待對象的到來
else{
map.set(n, i);
}
}
return '沒有目標匹配';
}
console.log(twoSum([1, 2, 3, 4], 6)) //[1, 3]
複製代碼
1)題意
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
輸入輸出示例:
輸入: s = "abcabcbb"
輸出: 3
解釋:
"abc"
,因此其長度爲 3
。2)解題思路
3)解題步驟
4)代碼實現
/** * @param {string} s * @return {number} */
let lengthOfLongestSubstring = function(s){
let l = 0;
let res = 0;
const map = new Map();
for(let r = 0; r < s.length; r++){
// map.get(r) >= l 確保下標在左指針右邊
if(map.has(s[r]) && map.get(s[r]) >= l){
l = map.get(s[r]) + 1;
}
res = Math.max(res, r - l + 1);
map.set(s[r], r);
}
return res;
}
console.log(lengthOfLongestSubstring('ssdfsf')) // 3
複製代碼
1)題意
給你一個字符串 s
、一個字符串 t
。返回 s
中涵蓋 t
全部字符的最小子串。若是 s
中不存在涵蓋 t
全部字符的子串,則返回空字符串 ""
。
**注意:**若是 s
中存在這樣的子串,咱們保證它是惟一的答案。
輸入輸出示例:
BANC
覆蓋 ABC
三個字母,而且是最小子串。2)解題思路
T
的子串。3)解題步驟
T
的子串,移動左指針,儘可能減小包含 T
的子串的長度。4)代碼實現
/** * @param {string} s * @param {string} t * @return {string} */
let minWindow = function(s, t){
// 用雙指針維護一個滑動窗口
// 指針初始位置都在第一個位置,即下標索引爲0
let l = 0;
let r = 0;
// 創建一個字典,用來表示子串須要的字符以及它的個數
const need = new Map();
for(let c of t){
// 遍歷子串的字符,存放到字典裏
need.set(c, need.has(c) ? need.get(c) + 1 : 1);
}
// 須要的類型數量
let needType = need.size;
let res = '';
// 移動右指針
while(r < s.length){
// 在右指針不斷移動的過程當中,咱們不斷獲取當前的字符
const c = s[r];
// 判斷當前字符是否在咱們的需求列表裏面
if(need.has(c)){
need.set(c, need.get(c) - 1);
if (need.get(c) === 0){
needType -= 1;
}
}
while(needType === 0){
// 打印滑動窗口及表示的子串
// substring方法遵循左閉右開原則
// console.log(s.substring(l, r + 1));
const newRes = s.substring(l, r + 1);
// 找出最小的子串
if(!res || newRes.length < res.length){
res = newRes;
}
// c2表明左指針當前的字符
const c2 = s[l];
// 若是左指針在需求列表裏面
if(need.has(c2)){
// 字符的需求數量就須要增長
need.set(c2, need.get(c2) + 1);
// 若是字符需求數量爲1,原來是0,如今是1,那麼就從新須要此字符
if (need.get(c2) === 1){
needType += 1;
}
}
l += 1;
}//當跳出while循環時,意味着左指針不能再移動,要開始移動右指針
// 右指針移動則遞增1
r += 1;
}
return res;
}
console.log(minWindow('ASDFFGFGCX','AFG')) // ASDFFG
複製代碼
字典和集合能夠算是前端面試的必考題了,同時在平常開發中的使用頻率也相對較高,所以掌握字典和集合的內容是較爲重要的。
關於字典和集合在前端中的應用就講到這裏啦!但願對你們有幫助!
- 關注公衆號 星期一研究室 ,第一時間關注學習乾貨,更多精彩專欄待你解鎖~
- 若是這篇文章對你有用,記得 一鍵三連 再走哦~
- 不期而遇,咱們下期見!🥂🥂🥂