【墨鳌】【力扣 208. 实现 Trie (前缀树)】【数据结构】【HashSet + HashMap + Trie树】
题目描述
实现一颗字典树
跳转链接
Jump To Problem
Jump To Solution
代码
import java.util.ArrayList;
import java.util.Iterator;
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 contains(K key) {
int index=hash(key, numBuckets);
for(K k: buckets.get(index))
if(key.equals(k)){
return true;
}
return false;
}
public void add(K key) {
if (key == null) return;
if (((double) this.numEntries / (double) this.numBuckets) >= this.loadFactor) enlarge();
if (contains(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 (!contains(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 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);
// return Math.floorMod(hash(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.contains(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.add(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 Trie {
private HAMap<Character,Trie> children;
private boolean isWord;
/** Initialize your data structure here. */
public Trie() {
children = new HAMap<>();
isWord = false;
}
/** Inserts a word into the trie. */
public void insert(String word) {
Trie node = this;//node先指向根节点
for(int i = 0; i < word.length(); i++){
char c = word.charAt(i);
if(!node.children.containsKey(c)){
node.children.put(c,new Trie());
}
node = node.children.get(c);
}
node.isWord = true;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Trie find = this;
for(int i = 0; i < word.length(); i++){
char c = word.charAt(i);
if(find.children.containsKey(c)){
find = find.children.get(c);
}else{
return false;
}
}
if(find.isWord == true){
return true;
}else{
return false;
}
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Trie cur = this;
for(int i = 0; i < prefix.length(); i++){
char c = prefix.charAt(i);
if(!cur.children.containsKey(c)){
return false;
}
cur = cur.children.get(c);
}
return true;
}
}
~~Jason_liu O(∩_∩)O