前端必会数据结构与算法系列之集合与字典(五)

611 阅读3分钟

1. 什么是集合

集合是由一组无序且唯一(即不能重复)的项组成的,可以把集合想象成一个既没有重复元素,也没有顺序概念的数组。在JavaScript中集合的实现为Set()

集合常用操作:

  1. 去重
  2. 判断某元素是否在集合中
  3. 求交集/差集/并集
// 去重
const arr = [1, 1, 2, 2];
const arr2 = [...new Set(arr)];

// 判断元素是否在集合中
const set = new Set(arr);
const has = set.has(3);

// 求交集
const set2 = new Set([2, 3]);
const set3 = new Set([...set].filter(item => set2.has(item)));

2. 实现一个集合

我们尝试自己来实现集合,以下是集合的常用API。

  • add(element):向集合添加一个新元素。
  • delete(element):从集合移除一个元素。
  • has(element):如果元素在集合中,返回 true,否则返回 false。
  • clear():移除集合中的所有元素。
  • size():返回集合所包含元素的数量。它与数组的 length 属性类似。
  • values():返回一个包含集合中所有值(元素)的数组。
class Set {
    constructor () {
        this.items = {}
    }

    has (element) {
        return Object.prototype.hasOwnProperty.call(this.items, element)
    }

    add (element) {
        if (!this.has(element)) {
            this.items[element] = element
            return true
        }
        return false
    }

    delete (element) {
        if (this.has(element)) {
            delete this.items[element]
            return true
        }
        return false
    }

    clear () {
        this.items = {}
    }

    size () {
        return Object.keys(this.items).length
    }

    values () {
        return Object.values(this.items)
    }
}

JAVA Set实现:docs.oracle.com/en/java/jav…

3. 集合运算

  • 并集:对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。
  • 交集:对于给定的两个集合,返回一个包含两个集合中共有元素的新集合。
  • 差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合。
  • 子集:验证一个给定集合是否是另一集合的子集。

3.1 求并集

let union = a.concat(b.filter(v => !a.includes(v)))

new Set([...setA, ...setB])

3.2 求交集

原题地址:两个数组的交集

题解:两个数组的交集(多解法)

3.3 求差集

let difference = a.concat(b).filter(v => a.includes(v) && !b.includes(v))
new Set([...setA].filter(x => !setB.has(x)))

3.4 求子集

var intersection = function(nums1, nums2) {
    if (nums2.length < nums1.length) {
        return false
    }

    return nums1.every(value => {
        return nums2.include(value)
    })
}

4. 什么是字典

字典和集合很相似,集合以[值,值]的形式存储元素,字典则是以[键,值]的形式来存储元素。字典也称作映射、符号表或关联数组。js中字典由散列表实现,字典的表现形式为Object,Map。

5. 实现一个字典

defaultToString(item) {
    if (item === null) {
        return 'NULL';
    } if (item === undefined) {
        return 'UNDEFINED';
    } if (typeof item === 'string' || item instanceof String) {
        return `${item}`;
    }
    return item.toString();
}

class ValuePair {
    constructor(key, value) {
        this.key = key;
        this.value = value;
    }

    toString() {
        return `[#${this.key}: ${this.value}]`;
    }
}

class Dictionary {
    constructor(toStrFn = defaultToString) {
        this.toStrFn = toStrFn;
        this.table = {};
    }

    set(key, value) {
        if (key != null && value != null) {
            const tableKey = this.toStrFn(key);
            this.table[tableKey] = new ValuePair(key, value);
            return true;
        }
        return false;
    }

    get(key) {
        const valuePair = this.table[this.toStrFn(key)];
        return valuePair == null ? undefined : valuePair.value;
    }

    hasKey(key) {
        return this.table[this.toStrFn(key)] != null;
    }

    remove(key) {
        if (this.hasKey(key)) {
            delete this.table[this.toStrFn(key)];
            return true;
        }
        return false;
    }

    values() {
        return this.keyValues().map(valuePair => valuePair.value);
    }

    keys() {
        return this.keyValues().map(valuePair => valuePair.key);
    }

    keyValues() {
        return Object.values(this.table);
    }

    forEach(callbackFn) {
        const valuePairs = this.keyValues();
        for (let i = 0; i < valuePairs.length; i++) {
            const result = callbackFn(valuePairs[i].key, valuePairs[i].value);
            if (result === false) {
                break;
            }
        }
    }

    isEmpty() {
        return this.size() === 0;
    }

    size() {
        return Object.keys(this.table).length;
    }

    clear() {
        this.table = {};
    }
}

JAVA Map实现:docs.oracle.com/en/java/jav…

6. leetcode常见考题

6.1 简单

1. 两个数组的交集

难度: 简单

题解:两个数组的交集(多解法)

2. 两数之和

难度:简单

题解:两数之和(字典)

3. 有效的字母异位词

难度:简单

题解:有效的字母异位词

6.2 中等

1. 无重复字符的最长子串

难度:中等

题解:无重复字符的最长子串(滑动窗口)

2. 字母异位词分组

难度:中等

题解:字母异位词分组

6.3 困难

1. 最小覆盖子串

难度:困难

题解:最小覆盖子串(滑动窗口)

详解请参考:leetcode刷题之路

持续更新ing...