HashMap
Copyright © 直通硅谷
http://www.zhitongguigu.com/


Map and Set are most important data structures we use in development
Copyright © 直通硅谷
http://www.zhitongguigu.com/
There are multiple different maps and sets that are in Java
HashMap
Java: Map<A,B>
Map<String, Integer> hm = new HashMap<>();
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Basic Operations
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Return Type | Method |
---|---|
Value 🤔 | put(key, value) |
Value | get(key) |
Value | remove(key) |
boolean | containsKey(key) |
boolean | containsValue(value) |
Set<Map.Entry<Key, Value>> | entrySet() |
Set<Key> | keySet() |
Collection<Value> | values() |
... | size(); isEmpty(); putAll(Map<>); |
Key: Object; Value: Object
Basic operations
Copyright © 直通硅谷
http://www.zhitongguigu.com/
hashmap : [<"apple", 1>, <"pear", 1>]
hashmap.put("banana", 3);
hashmap.remove("apple");
hashmap.get("pear");
hashmap.containsKey("kiwi");
hashmap.containsValue(3);
not a good one to use
Time complexity for HashMap
Copyright © 直通硅谷
http://www.zhitongguigu.com/
- add
- remove
- get
- containsKey
- containsValue
- O(1)
- O(1)
- O(1)
- O(1)
- O(n)
Traverse a HashMap
Copyright © 直通硅谷
http://www.zhitongguigu.com/
// Map -> Set -> Iterator -> Map.Entry -> troublesome, not recommend!
Iterator<Entry<String,String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String,String> entry = (Map.Entry<String,String>) iterator.next();
System.out.println("Key: " + entry.getKey() + " Value:" + entry.getValue());
}
// more elegant way, this should be the standard way, recommend!
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
}
// weired, but works anyway, not recommend!
for (Object key : map.keySet()) {
System.out.println("Key: " + key.toString() + " Value: " + map.get(key));
}
So always use the second way!
🤔
🤔
Hashing
Copyright © 直通硅谷
http://www.zhitongguigu.com/

collision
Hash Function
Copyright © 直通硅谷
http://www.zhitongguigu.com/
a function that can take a key and compute an integer (or an index in a table) for it
What really matters: How could we find a hash function that could fast compute the index without collisions
Hash Function
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Division:
X - Number of slots
A - Key as int
A mod X to get index
Example:
<X = 17, A = 35> <X = 17, A = 6>
35%17 = 1; 8%17 = 8
Hash Function Division
Copyright © 直通硅谷
http://www.zhitongguigu.com/

Hash Function Division
Copyright © 直通硅谷
http://www.zhitongguigu.com/

Hash Function Java String
Copyright © 直通硅谷
http://www.zhitongguigu.com/
// hash default 0
public int More hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
Hash Function Joshua Bloch
Copyright © 直通硅谷
http://www.zhitongguigu.com/
1. Create a int result and assign a non-zero value.
2. For every field f tested in the equals() method, calculate a hash code c by:
- If the field f is a boolean: calculate (f ? 0 : 1);
- If the field f is a byte, char, short or int: calculate (int)f;
- If the field f is a long: calculate (int)(f ^ (f >>> 32));
- If the field f is a float: calculate Float.floatToIntBits(f);
- If the field f is a double: calculate Double.doubleToLongBits(f)
and handle the return value like every long value;
- If the field f is an object: Use the result of the hashCode()
method or 0 if f == null;
- If the field f is an array: see every field as separate element
and calculate the hash value in a recursive fashion and combine
the values as described next.
3. Combine the hash value c with result:
result = 37 * result + c;
4. Return result
// This should result in a proper distribution of hash values for most use situations.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int hashCode() {
// Start with a non-zero constant. Prime is preferred
int result = 17;
// Include a hash for each field.
// Primatives
result = 31 * result + (booleanField ? 1 : 0); // 1 bit » 32-bit
result = 31 * result + byteField; // 8 bits » 32-bit
result = 31 * result + charField; // 16 bits » 32-bit
result = 31 * result + shortField; // 16 bits » 32-bit
result = 31 * result + intField; // 32 bits » 32-bit
result = 31 * result + (int)(longField ^ (longField >>> 32)); // 64 bits » 32-bit
result = 31 * result + Float.floatToIntBits(floatField); // 32 bits » 32-bit
long doubleFieldBits = Double.doubleToLongBits(doubleField); // 64 bits (double) » 64-bit (long) » 32-bit (int)
result = 31 * result + (int)(doubleFieldBits ^ (doubleFieldBits >>> 32));
// Objects
result = 31 * result + Arrays.hashCode(arrayField); // var bits » 32-bit
result = 31 * result + referenceField.hashCode(); // var bits » 32-bit (non-nullable)
result = 31 * result + // var bits » 32-bit (nullable)
(nullableReferenceField == null
? 0
: nullableReferenceField.hashCode());
return result;
}
Hash Function Joshua Bloch
Collision
Copyright © 直通硅谷
http://www.zhitongguigu.com/

Collision
Copyright © 直通硅谷
http://www.zhitongguigu.com/
No matter which function, you are using, you have to deal with collision
reason that there is collision:
- hash function is not perfect
- some keys just happen to map to the same index
- keys > slots
Collision
Copyright © 直通硅谷
http://www.zhitongguigu.com/
How to solve them:
- We cannot, just try to find a better algo
- Open hashing
- Closed hashing
- Expand the space (Load Factor)
Load factor: size/capacity
Normally if (LF > 0.75), we double the space.
Collision
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Open hashing:
for each collision, we use a linked list to store them
Closed hashing:
we store them in somewhere else in the table
Open hashing
Copyright © 直通硅谷
http://www.zhitongguigu.com/

🤔get(16);
🤔remove(24);
Closed hashing
Copyright © 直通硅谷
http://www.zhitongguigu.com/

🤔get(16);
🤔remove(24);
Hash Function Key Points
Copyright © 直通硅谷
http://www.zhitongguigu.com/
- Hash function is not random, given the same key, you can always find the corresponding hashing value.
- Easy and quick to compute.
- Distribution as even as possible
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
These two functions are very important in Java
We can override them and it will affect our HashMap collision and basic operations
Can we have Map<int, Object>?🤔
Hashcode & Equals example
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Test{
private int num;
private String data;
public boolean equals(Object obj){
if(this == obj) {
return true;
}
if((obj == null) || (obj.getClass() != this.getClass())) {
return false;
}
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
public int hashCode(){
int hash = 7;
hash = 31 * hash + num;
hash = 31 * hash + (null == data ? 0 : data.hashCode());
return hash;
}
// other methods...
}
🤔
Override & Overload
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public boolean equals(Test test){
if(this == test) {
return true;
}
if((test == null)) {
return false;
}
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
@Override
public boolean equals(Object obj){
if(this == obj) {
return true;
}
if((obj == null) || (obj.getClass() != this.getClass())) {
return false;
}
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
class Dog{
public void bark(){
System.out.println("woof ");
}
//overloading method
public void bark(int num){
for(int i=0; i<num; i++)
System.out.println("woof ");
}
}
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
🤔equals <-> hashcode
equals --> hashcode
hashcode --> equals
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Primitive Type Wrapper class:
Integer, Short, Long, Byte,Char, Float, Double, Boolean
For these class, equals is same as ==
🤔
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
class D {
public static void main(String args[]) {
Integer b2=128;
Integer b3=128;
System.out.println(b2==b3);
}
}
// Output: false
class D {
public static void main(String args[]) {
Integer b2=127;
Integer b3=127;
System.out.println(b2==b3);
}
}
// Output: true
// This Integer caching works only on autoboxing
Integer b2 =Integer.valueOf(127)
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Primitive Type Wrapper class:
Short, Long, Byte, Char, Float, Double, Boolean
For these class, equals is same as ==
Unless compare primitive type. Don't use ==
Don't rely on two references being identical.
Always use .equals()
Should always override .equals() for data objects.
If no override, find its parent class till Object (==)
Hashcode & Equals
Copyright © 直通硅谷
http://www.zhitongguigu.com/
During implementation
If obj1.equals(obj2) return true
then must have
obj1.hashcode() == obj2.hashcode()
// Object equals will be same as ==
public boolean equals(Object obj) {
return (this == obj);
}
Java Map & Set
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Hash | Tree | LinkedHash | |
---|---|---|---|
Map | HashMap | TreeMap | LinkedHashMap |
Set | HashSet | TreeSet | LinkedHashSet |
Copyright © 直通硅谷
http://www.zhitongguigu.com/

Different Maps and Sets
Two Sum
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an array of integers (no duplicate),
find two numbers such that they add up to a specific target number.
The function twoSum should return the two numbers such that
they add up to the target, where number1 must be less than number2.
You may assume that each input would have exactly one solution.
Example:
Input: numbers={2, 7, 11, 15}, target=9
Output: {2, 7}
public int[] twoSum(int[] nums, int target) {
// TODO: implement this function.
}
Two Sum [Return Value]
Two Sum [Return Index]
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Difference?
What's the previous question?
What's the previous solution?
Will it work?
Given an array of integers, return indices of the two numbers
such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]
🤔
Two Sum [Return Index]
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an array of integers, return indices of the two numbers
such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]
Two Sum Return Value | Two Sum Return Index | |
---|---|---|
Map | current hw | current example |
Sort | previous hw | [harder]optional hw |
🤔
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[] { i, map.get(complement) };
}
}
throw new IllegalArgumentException("No two sum solution");
}
Two Sum [Return Index]
🤔
duplicates? [4, 2, 4] t=8
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] {map.get(complement), i};
}
map.put(nums[i], i);
}
return null;
}
Two Sum [Return Index]
Time | Space | |
---|---|---|
Sort | ||
HashMap |
O(nlogn)
O(1)
O(n)
O(n)
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given a pattern and a string str, find if str follows the same pattern.
pattern = "abba", str = "dog cat cat dog" should return true.
pattern = "abba", str = "dog cat cat fish" should return false.
pattern = "aaaa", str = "dog cat cat dog" should return false.
pattern = "abba", str = "dog dog dog dog" should return false.
Notes:
- You may assume pattern contains only lowercase letters,
- str contains lowercase letters separated by a single space.
Word Pattern
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public boolean wordPattern(String pattern, String str) {
Map<Character, String> hm = new HashMap<>();
Map<String, Character> hm_r = new HashMap<>();
String[] words = str.split(" ");
if (pattern.length() != words.length) {
return false;
}
for (int i = 0; i < pattern.length(); i++) {
char a = pattern.charAt(i);
String b = words[i];
if (!hm.containsKey(a)) {
hm.put(a, b);
} else if (!hm.get(a).equals(b)){
return false;
}
if (!hm_r.containsKey(b)) {
hm_r.put(b, a);
} else if (hm_r.get(b) != a) {
return false;
}
}
return true;
}
}
🤔
word
&
char
Word Pattern
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public boolean wordPattern(String pattern, String str) {
Map<Character, Integer> hm = new HashMap<>();
Map<String, Integer> hm_r = new HashMap<>();
String[] words = str.split(" ");
if (pattern.length() != words.length) {
return false;
}
for (int i = 0; i < pattern.length(); i++) {
if (!Objects.equals(hm.put(pattern.charAt(i), i), hm_r.put(words[i], i))) {
return false;
}
}
return true;
}
- Use the return value of put method
- Character - index - String
Word Pattern
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public boolean wordPattern(String pattern, String str) {
Map<Object, Object> hm = new HashMap<>();
String[] words = str.split(" ");
if (words.length != pattern.length())
return false;
for (int i=0; i<words.length; i++)
if (!Objects.equals(hm.put(pattern.charAt(i), i), hm.put(words[i], i)))
return false;
return true;
}
public boolean wordPattern(String pattern, String str) {
Map hm = new HashMap();
String[] words = str.split(" ");
if (words.length != pattern.length())
return false;
for (int i=0; i<words.length; i++)
if (!Objects.equals(hm.put(pattern.charAt(i), i), hm.put(words[i], i)))
return false;
return true;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an array of strings, group anagrams together.
For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"]
Note
- For the return value, each inner list's elements must follow the lexicographic order.
- All inputs will be in lower-case.
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
Group Anagrams
Copyright © 直通硅谷
http://www.zhitongguigu.com/
How to know two words are anagrams?
"ate" and "eat" ->
when we sort them, ate and eat both become "aet"
So we need a hashmap to tell if we already have the list or not.
Group Anagrams
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, List<String>> stringmap = new HashMap();
List<List<String>> result = new ArrayList();
for(String str: strs) {
char[] chars = str.toCharArray();
Arrays.sort(chars);
String sorted = new String(chars);
if(stringmap.containsKey(sorted)) {
stringmap.get(sorted).add(str);
} else {
ArrayList<String> stringList = new ArrayList();
stringList.add(str);
stringmap.put(sorted, stringList);
}
}
for(Map.Entry<String, List<String>> entry: stringmap.entrySet()) {
List stringresult = entry.getValue();
Collections.sort(stringresult);
result.add(stringresult);
}
return result;
}
🤔
Group Anagrams
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, List<String>> hm = new HashMap();
List<List<String>> result = new ArrayList();
for(String s: strs) {
char[] chars = s.toCharArray();
Arrays.sort(chars);
String sorted = new String(chars);
if(!hm.containsKey(sorted)) {
hm.put(sorted, new ArrayList());
}
hm.get(sorted).add(s);
}
// keySet -> list and sort will make outer list lexicographic
for (List<String> list : hm.values()) {
Collections.sort(list);
result.add(list);
}
// for (String key : hm.keySet()) {
// Collections.sort(hm.get(key));
// result.add(hm.get(key));
// }
return result;
}
Group Anagrams
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an array of strings, group anagrams together.
For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"]
Note
- For the return value, each inner list's elements must follow the lexicographic order.
- All inputs will be in lower-case.
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
What about no sorting?
🤔
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3.
Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abbcdefdgh", the answer is "bcdef", which the length is 5.
0 1 2 3 4 5 6 7 8 9
a b b c d e f d g h
_ _ i _ _ _ _ j _ _
// Sliding Window
// Two Pointers
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int lengthOfLongestSubstring(String s) {
int result = 0;
if (s == null || s.length() == 0) {
return 0;
}
char[] arr = s.toCharArray();
Map<Character, Integer> hm = new HashMap<>();
for (int i = 0, j = 0; i < arr.length; i++) {
char c = arr[i];
if (hm.containsKey(c)) {
j = Math.max(j, hm.get(c) + 1);
}
hm.put(c,i);
result = Math.max(result, i - j + 1);
}
return result;
}
🤔You may not use Map
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int lengthOfLongestSubstring(String s) {
int result = 0;
int[] cache = new int[256];
for (int i = 0, j = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (cache[c] > 0) {
j = Math.max(j, cache[c]);
}
cache[c] = i + 1;
result = Math.max(result, i - j + 1);
}
return result;
}
The idea of Hashing
🤔Is cache[c] > 0 necessary?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int lengthOfLongestSubstring(String s) {
int result = 0;
int[] cache = new int[256];
for (int i = 0, j = 0; i < s.length(); i++) {
j = Math.max(j, cache[s.charAt(i)]);
cache[s.charAt(i)] = i + 1;
result = Math.max(result, i - j + 1);
}
return result;
}
🤔You may not use 256 space
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public int lengthOfLongestSubstring(String s) {
int result = 0;
int[] cache = new int[128];
for (int i = 0, j = 0; i < s.length(); i++) {
j = Math.max(j, cache[s.charAt(i)]);
cache[s.charAt(i)] = i + 1;
result = Math.max(result, i - j + 1);
}
return result;
}
// If only low case is used
public int lengthOfLongestSubstring(String s) {
int result = 0;
int[] cache = new int[26];
for (int i = 0, j = 0; i < s.length(); i++) {
j = Math.max(j, cache[s.charAt(i) - 'a']);
cache[s.charAt(i) - 'a'] = i + 1;
result = Math.max(result, i - j + 1);
}
return result;
}
HashSet
HashMap | HashSet |
---|---|
put(key, value) | add(element) |
get(key) | |
remove(key) | remove(object) |
containsKey(key) | contains(object) |
containsValue(value) | |
entrySet() | |
keySet() | |
values() | |
size(); isEmpty(); putAll(Map<>); | size(); isEmpty(); addAll(Collection); |
Java Map & Set
Copyright © 直通硅谷
http://www.zhitongguigu.com/
╔══════════════╦═════════════════════╦═══════════════════╦══════════════════════╗
║ Property ║ HashMap ║ TreeMap ║ LinkedHashMap ║
╠══════════════╬═════════════════════╬═══════════════════╬══════════════════════╣
║ ║ no guarantee order ║ sorted according ║ ║
║ Order ║ will remain constant║ to the natural ║ insertion-order ║
║ ║ over time ║ ordering ║ ║
╠══════════════╬═════════════════════╬═══════════════════╬══════════════════════╣
║ Get/put ║ ║ ║ ║
║ remove ║ O(1) ║ O(log(n)) ║ O(1) ║
║ containsKey ║ ║ ║ ║
╠══════════════╬═════════════════════╬═══════════════════╬══════════════════════╣
║ ║ ║ NavigableMap ║ ║
║ Interfaces ║ Map ║ Map ║ Map ║
║ ║ ║ SortedMap ║ ║
╠══════════════╬═════════════════════╬═══════════════════╬══════════════════════╣
║ ║ ║ ║ ║
║ Null ║ allowed ║ only values ║ allowed ║
║ values/keys ║ ║ ║ ║
╠══════════════╬═════════════════════╩═══════════════════╩══════════════════════╣
║ ║ Fail-fast behavior of an iterator cannot be guaranteed ║
║ Fail-fast ║ impossible to make any hard guarantees in the presence of ║
║ behavior ║ unsynchronized concurrent modification ║
╠══════════════╬═════════════════════╦═══════════════════╦══════════════════════╣
║ ║ ║ ║ ║
║Implementation║ buckets ║ Red-Black Tree ║ double-linked ║
║ ║ ║ ║ buckets ║
╠══════════════╬═════════════════════╩═══════════════════╩══════════════════════╣
║ Is ║ ║
║ synchronized ║ implementation is not synchronized ║
╚══════════════╩════════════════════════════════════════════════════════════════╝
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Homework 7:
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Required
- Two Sum [Return Value] use HM
- Happy Number
- Isomorphic Strings
- Minimum Window Substring [hard]
- Substring with Concatenation of All Words [hard]
[GoValley-201612] HashMap
By govalley201612
[GoValley-201612] HashMap
20161230 HashMap
- 1,004