【墨鳌】【力扣 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;
}
}
~~Jason_liu O(∩_∩)O