Hash Table
is a data structure which organizes data using hash functions
in order to support quick insertion and search
. In this article, we will take a look at the principle of the hash table.
一 自己定义一个HashSet的基本操作
MyHashSet hashSet = new MyHashSet();
hashSet.add(1);
hashSet.add(2);
hashSet.contains(1); // returns true
hashSet.contains(3); // returns false (not found)
hashSet.add(2);
hashSet.contains(2); // returns true
hashSet.remove(2);
hashSet.contains(2); // returns false (already removed)
代码
class MyHashSet {
private final int MAX_LEN = 100000; // the amount of buckets
private List<Integer>[] set; // hash set implemented by array
/** Initialize your data structure here. */
public MyHashSet() {
set = (List<Integer>[])new ArrayList[MAX_LEN];
}
/** Returns the corresponding bucket index. */
private int getIndex(int key) {
return key % MAX_LEN;
}
/** Search the key in a specific bucket. Returns -1 if the key does not existed. */
private int getPos(int key, int index) {
// Each bucket contains a list.
List<Integer> temp = set[index];
if (temp == null) {
return -1;
}
// Iterate all the elements in the bucket to find the target key.
for (int i = 0; i < temp.size(); ++i) {
if (temp.get(i) == key) {
return i;
}
}
return -1;
}
public void add(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
// Add new key if key does not exist.
if (set[index] == null) {
set[index] = new ArrayList<Integer>();
}
set[index].add(key);
}
}
public void remove(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos >= 0) {
// Remove the key if key exists.
set[index].remove(pos);
}
}
/** Returns true if this set did not already contain the specified element */
public boolean contains(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
return pos >= 0;
}
}
/**
* Your MyHashSet object will be instantiated and called as such:
* MyHashSet obj = new MyHashSet();
* obj.add(key);
* obj.remove(key);
* boolean param_3 = obj.contains(key);
*/
The Principle of Built-in Hash Table
The typical design of built-in hash table is:
- The key value can be any
hashable
type. And a value which belongs to a hashable type will have ahashcode
. This code will be used in the mapping function to get the bucket index. - Each bucket contains
an array
to store all the values in the same bucket initially. - If there are too many values in the same bucket, these values will be maintained in a
height-balanced binary search tree
instead.
The average time complexity of both insertion and search is still O(1)
. And the time complexity in the worst case is O(logN)
for both insertion and search by using height-balanced BST. It is a trade-off between insertion and search.
二 Java HashSet的用法
// "static void main" must be defined in a public class.
public class Main {
public static void main(String[] args) {
// 1. initialize the hash set
Set<Integer> hashSet = new HashSet<>();
// 2. add a new key
hashSet.add(3);
hashSet.add(2);
hashSet.add(1);
// 3. remove the key
hashSet.remove(2);
// 4. check if the key is in the hash set
if (!hashSet.contains(2)) {
System.out.println("Key 2 is not in the hash set.");
}
// 5. get the size of the hash set
System.out.println("The size of has set is: " + hashSet.size());
// 6. iterate the hash set
for (Integer i : hashSet) {
System.out.print(i + " ");
}
System.out.println("are in the hash set.");
// 7. clear the hash set
hashSet.clear();
// 8. check if the hash set is empty
if (hashSet.isEmpty()) {
System.out.println("hash set is empty now!");
}
}
}
三 例题:
217 Contains Duplicate
Given an array of integers, find if the array contains any duplicates.
Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
Example 1:
Input: [1,2,3,1] Output: true
Example 2:
Input: [1,2,3,4] Output: false
Approach #1 HashSet 我的解法
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for(Integer i : nums){
if(set.contains(i))
return true;
else
set.add(i);
}
return false;
}
}
Complexity Analysis
-
Time complexity : O(n). We do
search()
andinsert()
for n times and each operation takes constant time. -
Space complexity : O(n). The space used by a hash table is linear with the number of elements in it.
136 Single Number
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
Input: [2,2,1] Output: 1
Example 2:
Input: [4,1,2,1,2] Output: 4
Approach #1 Hash Set 我的解法
class Solution {
public int singleNumber(int[] nums) {
Set<Integer> hashSet = new HashSet<>();
for(int n: nums){
if(hashSet.contains(n))
hashSet.remove(n);
else
hashSet.add(n);
}
int ans = 0;
for(Integer i: hashSet){
ans = i;
}
return ans;
}
}
Complexity Analysis
-
Time complexity : O(n \cdot 1) = O(n)O(n⋅1)=O(n). Time complexity of
for
loop is O(n)O(n). Time complexity of hash table(dictionary in python) operationpop
is O(1)O(1). -
Space complexity : O(n)O(n). The space required by hash\_tablehash_table is equal to the number of elements in \text{nums}nums.
349. Intersection of Two Arrays
Given two arrays, write a function to compute their intersection.
Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2] Output: [2]
Example 2:
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] Output: [9,4]
Note:
- Each element in the result must be unique.
- The result can be in any order.
我的解法
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> hashSet = new HashSet<>();
Set<Integer> hs1 = new HashSet<>();
Set<Integer> hs2 = new HashSet<>();
for(int a: nums1) hs1.add(a);
for(int b: nums2) hs2.add(b);
for(int n: nums1){
if(hs1.contains(n)&&hs2.contains(n)){
hashSet.add(n);
}
}
int[] ans = new int[hashSet.size()];
int i = 0;
for(Integer h: hashSet) ans[i++] = h;
return ans;
}
}
202. Happy Number
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Example:
Input: 19 Output: true Explanation: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
class Solution {
public boolean isHappy(int n) {
Set<Integer> inLoop = new HashSet<Integer>();
int squareSum,remain;
while (inLoop.add(n)) {
squareSum = 0;
while (n > 0) {
remain = n%10;
squareSum += remain*remain;
n /= 10;
}
if (squareSum == 1)
return true;
else
n = squareSum;
}
return false;
}
}