【墨鳌】【力扣 219. 存在重复元素 II】【数据结构】【链表法实现 HashSet & HashMap】

思路

经过简化,其实只需要记录是否存在即可
所以可以只手写 HashSet

HashSet代码

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Hash-based Set
 */
class HASet<K> implements Iterable<K> {

    @Override
    public Iterator<K> iterator() {
        return new HASetIterator();
    }

    private class HASetIterator implements Iterator<K> {
        private int index;
        private ArrayList<K> keys;

        public HASetIterator() {
            index = 0;
            keys = new ArrayList<>();
            for (ArrayList<K> bucket : buckets) {
                for (K key : bucket)
                    keys.add(key);
            }
        }

        @Override
        public boolean hasNext() {
            return index < numEntries;
        }

        @Override
        public K next() {
            return keys.get(index++);
        }
    }

    private static final int DEFAULT_CAPACITY = 16;
    private static final double DEFAULT_LOAD_FACTOR = 1.5;

    private ArrayList<ArrayList<K>> buckets;
    private int numBuckets;
    private int numEntries;
    private final double loadFactor;

    public int size() {
        return numEntries;
    }

    public int getNumBuckets() {
        return numBuckets;
    }

    private int hash(K key) {
        int h = key.hashCode() & Integer.MAX_VALUE;
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    private int hash(K key, int mod) {
        return Math.floorMod(key.hashCode(), mod);
    }

    private void enlarge() {
        ArrayList<ArrayList<K>> newBuckets = new ArrayList<>();
        this.numBuckets *= 2;
        for (int i = 0; i < this.buckets.size() * 2; i++)
            newBuckets.add(new ArrayList<K>());
        for (ArrayList<K> bucket : buckets)
            for (K key : bucket) {
                int index = hash(key, this.numBuckets);
                newBuckets.get(index).add(key);
            }
        this.buckets = newBuckets;
    }

    public HASet(int initialCapacity, double loadFactor) {
        if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
        this.loadFactor = loadFactor;
        this.buckets = new ArrayList<>();
        for (int i = 0; i < initialCapacity; i++)
            this.buckets.add(new ArrayList<K>());
        this.numBuckets = initialCapacity;
        this.numEntries = 0;
    }

    public HASet() {
        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    public HASet(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public void clear() {
        for (ArrayList<K> bucket : buckets) bucket.clear();
        this.numEntries = 0;
    }

    public boolean containsKey(K key) {
        int index=hash(key, numBuckets);
        for(K k: buckets.get(index))
            if(key.equals(k)){
                return true;
            }
        return false;        
    }

    public void put(K key) {
        if (key == null) return;
        if (((double) this.numEntries / (double) this.numBuckets) >= this.loadFactor) enlarge();        
        if (containsKey(key)) {
            return;
        }
        int index = hash(key, numBuckets);
        this.buckets.get(index).add(key);
        this.numEntries++;
    }

    public K remove(K key) {
        if (key == null) return null;
        if (!containsKey(key)) return null;
        int index = hash(key, numBuckets);
        K removed = null;
        for (K k: buckets.get(index))
            if (key.equals(k)) {
                removed = k;
            }
        if (removed != null) {
            this.buckets.get(index).remove(removed);
            this.numEntries--;
            return removed;
        }
        return null;
    }

}

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        HASet<Integer> set=new HASet<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (i > k) set.remove(nums[i - k - 1]);
            if (set.containsKey(nums[i])) return true;
            set.put(nums[i]);
        }
        return false;
    }
}

HashSet + HashMap代码

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Hash-based Set
 */
class HASet<K> implements Iterable<K> {

    @Override
    public Iterator<K> iterator() {
        return new HASetIterator();
    }

    private class HASetIterator implements Iterator<K> {
        private int index;
        private ArrayList<K> keys;

        public HASetIterator() {
            index = 0;
            keys = new ArrayList<>();
            for (ArrayList<K> bucket : buckets) {
                for (K key : bucket)
                    keys.add(key);
            }
        }

        @Override
        public boolean hasNext() {
            return index < numEntries;
        }

        @Override
        public K next() {
            return keys.get(index++);
        }
    }

    private static final int DEFAULT_CAPACITY = 16;
    private static final double DEFAULT_LOAD_FACTOR = 1.5;

    private ArrayList<ArrayList<K>> buckets;
    private int numBuckets;
    private int numEntries;
    private final double loadFactor;

    public int size() {
        return numEntries;
    }

    public int getNumBuckets() {
        return numBuckets;
    }

    private int hash(K key) {
        int h = key.hashCode() & Integer.MAX_VALUE;
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    private int hash(K key, int mod) {
        return Math.floorMod(key.hashCode(), mod);
    }

    private void enlarge() {
        ArrayList<ArrayList<K>> newBuckets = new ArrayList<>();
        this.numBuckets *= 2;
        for (int i = 0; i < this.buckets.size() * 2; i++)
            newBuckets.add(new ArrayList<K>());
        for (ArrayList<K> bucket : buckets)
            for (K key : bucket) {
                int index = hash(key, this.numBuckets);
                newBuckets.get(index).add(key);
            }
        this.buckets = newBuckets;
    }

    public HASet(int initialCapacity, double loadFactor) {
        if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
        this.loadFactor = loadFactor;
        this.buckets = new ArrayList<>();
        for (int i = 0; i < initialCapacity; i++)
            this.buckets.add(new ArrayList<K>());
        this.numBuckets = initialCapacity;
        this.numEntries = 0;
    }

    public HASet() {
        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    public HASet(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public void clear() {
        for (ArrayList<K> bucket : buckets) bucket.clear();
        this.numEntries = 0;
    }

    public boolean containsKey(K key) {
        int index=hash(key, numBuckets);
        for(K k: buckets.get(index))
            if(key.equals(k)){
                return true;
            }
        return false;        
    }

    public void put(K key) {
        if (key == null) return;
        if (((double) this.numEntries / (double) this.numBuckets) >= this.loadFactor) enlarge();        
        if (containsKey(key)) {
            return;
        }
        int index = hash(key, numBuckets);
        this.buckets.get(index).add(key);
        this.numEntries++;
    }

    public K remove(K key) {
        if (key == null) return null;
        if (!containsKey(key)) return null;
        int index = hash(key, numBuckets);
        K removed = null;
        for (K k: buckets.get(index))
            if (key.equals(k)) {
                removed = k;
            }
        if (removed != null) {
            this.buckets.get(index).remove(removed);
            this.numEntries--;
            return removed;
        }
        return null;
    }

}

/**
 * Hash-based Map
 */
class HAMap<K, V> implements Iterable<K> {

    /**
     * Represents a key-value pair.
     */
    private class Entry {
        K key;
        V value;

        Entry(K k, V v) {
            key = k;
            value = v;
        }
    }

    private static final int DEFAULT_CAPACITY = 16;
    private static final double DEFAULT_LOAD_FACTOR = 1.5;

    private ArrayList<ArrayList<Entry>> buckets;
    private HASet<K> keySet;
    private int numBuckets;
    private int numEntries;
    private final double loadFactor;

    /**
     * @return a set of the keys contained in this map.
     */
    public HASet<K> keySet() {
        return keySet;
    }

    /**
     * @return the number of entries in this map.
     */
    public int size() {
        return numEntries;
    }

    /**
     * @return the number of buckets in this map.
     */
    public int getNumBuckets() {
        return numBuckets;
    }

    /*
     ***************************
     * DO NOT MODIFY CODE ABOVE
     ***************************
     */

    /*
     ***** HELPER METHODS START *****
     */
    
    private int keyHashValue(K key) {
        int h = key.hashCode() & Integer.MAX_VALUE;
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }    

    private int hash(K key, int mod) {
        return Math.floorMod(keyHashValue(key), mod);
    }

    private void enlarge() {
        ArrayList<ArrayList<Entry>> newBuckets = new ArrayList<>();
        this.numBuckets *= 2;
        for (int i = 0; i < this.buckets.size() * 2; i++)
            newBuckets.add(new ArrayList<Entry>());
        for (ArrayList<Entry> bucket : buckets)
            for (Entry entry : bucket) {
                int index = hash(entry.key, this.numBuckets);
                newBuckets.get(index).add(entry);
            }
        this.buckets = newBuckets;
    }

    /*
     ***** HELPER METHODS END *****
     */


    // LAB EXERCISE 12.2 CONSTRUCTORS

    public HAMap(int initialCapacity, double loadFactor) {
        if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
        this.loadFactor = loadFactor;
        this.keySet = new HASet<>();
        this.buckets = new ArrayList<>();
        for (int i = 0; i < initialCapacity; i++)
            this.buckets.add(new ArrayList<Entry>());
        this.numBuckets = initialCapacity;
        this.numEntries = 0;
    }

    public HAMap() {
        this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

    public HAMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }


    // LAB EXERCISE 12.3 CLEAR

    /**
     * Removes all of the entries from this map.
     */
    public void clear() {
        for (ArrayList<Entry> bucket : buckets) bucket.clear();
        this.keySet.clear();
        this.numEntries = 0;
    }


    // LAB EXERCISE 12.4 CONTAINS KEY and ITERATOR

    /**
     * @param key to be checked
     * @return true iff this map contains an entry with the specified key
     */
    public boolean containsKey(K key) {
        return this.keySet.containsKey(key);
    }

    /**
     * @return an Iterator that iterates over the stored keys
     */
    @Override
    public Iterator<K> iterator() {
        return this.keySet.iterator();
    }

    // CODING ASSIGNMENT 12.1 GET

    /**
     * @param key of the value to be returned
     * @return the value to which the specified key is mapped
     * null if this map contains no entries of the key
     */
    public V get(K key) {
        if (!containsKey(key)) return null;
        int index = hash(key, this.numBuckets);
        for (Entry entry : buckets.get(index))
            if (entry.key.equals(key)) return entry.value;
        return null;
    }

    // CODING ASSIGNMENT 12.2 PUT

    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained an entry with that key, the old value is replaced.
     * The key is not null.
     *
     * @param key   of the entry to be added
     * @param value of the entry to be added
     */
    public void put(K key, V value) {
        if (key == null) return;
        if (((double) this.numEntries / (double) this.numBuckets) >= this.loadFactor) enlarge();
        int index = hash(key, numBuckets);
        if (containsKey(key)) {
            /* replace the old value */
            for (Entry entry : buckets.get(index))
                if (entry.key.equals(key))
                    entry.value = value;
            return;
        }
        this.buckets.get(index).add(new Entry(key, value));
        this.keySet.put(key);
        this.numEntries++;
    }


    // CODING ASSIGNMENT 12.3 REMOVE

    /**
     * Removes the entry for the specified key only if it is
     * currently mapped to the specified value.
     *
     * @param key   of the entry to be removed
     * @param value of the entry to be removed
     * @return the value if entry found,
     * null otherwise
     */
    public V remove(K key, V value) {
        if (key == null) return null;
        if (!containsKey(key)) return null;
        int index = hash(key, numBuckets);
        Entry removed = null;
        for (Entry entry : buckets.get(index))
            if (key.equals(entry.key) && value.equals(entry.value)) {
                removed = entry;
            }
        if (removed != null) {
            this.buckets.get(index).remove(removed);
            this.numEntries--;
            this.keySet.remove(key);
            return removed.value;
        }
        return null;
    }

}

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        HAMap<Integer,Integer>map=new HAMap<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (i > k) map.remove(nums[i - k - 1], i - k - 1);
            if (map.containsKey(nums[i])) return true;
            map.put(nums[i],i);
        }
        return false;
    }
}
posted @ 2022-05-10 19:10  墨鳌  阅读(27)  评论(0编辑  收藏  举报