Copyright © 直通硅谷
http://www.zhitongguigu.com/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
There are multiple different maps and sets that are in Java
Map<String, Integer> hm = new HashMap<>();
Copyright © 直通硅谷
http://www.zhitongguigu.com/
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
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
Copyright © 直通硅谷
http://www.zhitongguigu.com/
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!
🤔
🤔
Copyright © 直通硅谷
http://www.zhitongguigu.com/
collision
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
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
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
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;
}
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;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
No matter which function, you are using, you have to deal with collision
reason that there is collision:
Copyright © 直通硅谷
http://www.zhitongguigu.com/
How to solve them:
Load factor: size/capacity
Normally if (LF > 0.75), we double the space.
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
Copyright © 直通硅谷
http://www.zhitongguigu.com/
🤔get(16);
🤔remove(24);
Copyright © 直通硅谷
http://www.zhitongguigu.com/
🤔get(16);
🤔remove(24);
Copyright © 直通硅谷
http://www.zhitongguigu.com/
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>?🤔
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...
}
🤔
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 ");
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
🤔equals <-> hashcode
equals --> hashcode
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 ==
🤔
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);
}
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 (==)
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);
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Hash | Tree | LinkedHash | |
---|---|---|---|
Map | HashMap | TreeMap | LinkedHashMap |
Set | HashSet | TreeSet | LinkedHashSet |
Copyright © 直通硅谷
http://www.zhitongguigu.com/
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]
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]
🤔
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");
}
🤔
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;
}
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:
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
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;
}
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
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
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.
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;
}
🤔
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;
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an array of strings, group anagrams together.
For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"]
Note
[
["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;
}
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); |
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/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Required