每週一練 之 資料結構與演算法(Set)

pingan8787發表於2019-05-05

這是第四周的練習題,五一放假結束,該收拾好狀態啦。

下面是之前分享的連結:

歡迎關注我的 個人主頁 && 個人部落格 && 個人知識庫 && 微信公眾號“前端自習課”

本週練習內容:資料結構與演算法 —— Set

這些都是資料結構與演算法,一部分方法是團隊其他成員實現的,一部分我自己做的,有什麼其他實現方法或錯誤,歡迎各位大佬指點,感謝。

一、集合是什麼?與它相關數學概念有哪些


解題:
1.集合定義:
集合(Set)是一種包含不同元素的資料結構。集合中的元素稱為成員,集合最重要的兩個特點:

  • 集合中的成員是無序;
  • 集合中不存在相同成員;

即:無序且唯一。

2.集合相關的數學概念:
集合的概念,如數學中一個由大於或等於0的整陣列成的自然數集合, N = { 0, 1, 2, ...}
還有如空集,表示不包含任何元素的集合。
並且也有並集,交集,差集等操作。

二、請實現一個集合,並實現以下方法

add(value):向集合新增一個新的項。
delete(value):從集合移除一個值。
has(value):如果值在集合中,返回 true,否則返回 false。
clear():移除集合中的所有項。
size():返回集合所包含元素的數量。與陣列的 length 屬性類似。
values():返回一個包含集合中所有值的陣列。


解題:

class Sets {
    constructor(){
        this.items = {}
    }
    has(value){
        // return value in this.items
        return this.items.hasOwnProperty(value)
    }
    add(value){
        if(!this.has(value)) {
            this.items[value] = value
            return true
        }
        return false
    }
    delete(value){
        if(!this.has(value)){
            delete this.items[value]
            return true
        }
        return false
    }
    clear(){
        this.items = {}
    }
    size(){
        const values = this.values()
        return values.length
    }
    values(){
        return Object.keys(this.items)
    }
}
複製程式碼

三、請實現集合的並集、交集、差集、子集操作

  • 並集(union):對於給定的兩個集合,返回一個包含兩個集合中所有元素的新集合。
  • 交集(intersection):對於給定的兩個集合,返回一個包含兩個集合中共用元素的新集合。
  • 差集(difference):對於給定的兩個集合,返回一個包含所有存在於第一個集合且不存在於第二個集合的元素的新集合。
  • 子集(subset):驗證一個給定集合是否是另一個集合的子集。

解題:

/**
 * union 並集
 * @param {Object} otherSet 其他集合
 */
Sets.prototype.union = function(otherSet){
    let result = new Sets(),
        current = this.values(),
        other = otherSet.values()
    for(let i = 0; i < current.length; i++){
        result.add(current[i])
    }
    for(let i = 0; i < other.length; i++){
        result.add(other[i])
    }
    return result
}


/**
 * intersection 交集
 * @param {Object} otherSet 其他集合
 */
Sets.prototype.intersection = function(otherSet){
    let result = new Sets(),
        current = this.values()
    for(let i = 0; i < current.length; i++){
        if(otherSet.has(current[i])){
            result.add(current[i])
        }
    }
    return result
}


/**
 * difference 差集
 * @param {Object} otherSet 其他集合
 */
Sets.prototype.difference = function(otherSet){
    let result = new Sets(),
        current = this.values()
    for(let i = 0; i < current.length; i++){
        if(!otherSet.has(current[i])){
            result.add(current[i])
        }
    }
    return result
}



/**
 * subset 子集
 * @param {Object} otherSet 其他集合
 */
Sets.prototype.subset = function(otherSet){
    let result = new Sets(),
        current = this.values()

    if(this.size() > otherSet.size()) return false
    for(let i = 0; i < current.length; i++){
        if(!otherSet.has(current[i])){
            return false
        }
    }
    return true
}
複製程式碼

四、給定兩個陣列,編寫一個 intersection() 函式來計算它們的交集

使用示例如下:

const nums1 = [1, 2, 2, 1];
const nums2 = [2, 2];
const nums3 = [4, 9, 5];
const nums4 = [9, 4, 9, 8, 4];

intersection(nums1, nums2); // [2]
intersection(nums3, nums4); // [9, 4]
複製程式碼

提示:輸出結果中的每個元素是唯一的,可以不考慮輸出結果的順序。


解題:

function intersection(arr1, arr2){
    if(!Array.isArray(arr1) || !Array.isArray(arr2)) return []
    let create = function(arr){
        let sets = new Sets()
        arr.map(item => sets.add(item))
        return sets
    }
    let Sets1 = create(arr1)
    let Sets2 = create(arr2)
    let result = Sets1.intersection(Sets2)
    return  result.values()
}
複製程式碼

五、給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集

使用示例如下:

const nums = [1, 2, 3];
subsets(nums);
// 輸出以下結果:
[
  [3],
  [1],
  [2],
  [1, 2, 3],
  [1, 3],
  [2, 3],
  [1, 2],
  []
]
複製程式碼

來源:leetcode 78.集合


解題:

目前網路上的最優解:

function subsets(nums){
    if(!nums || !Array.isArray(nums)) return []
    
    function diff (num, vec) {
        let tmp = vec.slice(0)
        result.push(tmp)
        for (let i = num; i < len; i++) {
            vec.push(nums[i])
            diff(i + 1, vec)
            vec.splice(-1)
        }
    }

    const len = nums.length
    let arr = [], result = []
    diff(0, arr)
    return result
}
複製程式碼

窮舉法:

function subsets(nums){
    if(!nums || !Array.isArray(nums)) return []

    let result = [[]],
        len = nums.length
    if(len === 0) return result 
    for(let i = 0; i < len; i++){
        let l = result.length
        let num = nums[i]
        let array = [num]
        for(let j = 0; j < l; j++){
            let tmparray = result[j].concat(array)
            result.push(tmparray)
        }
    }
    return result
}
複製程式碼

下週預告

下週將練習Dictionary 和 HashTable 的題目。

相關文章