1.典型應用場景java
2.集合接口node
public interface Set<E> { // 集合不存放相同元素 void add(E e); // 刪除元素 void remove(E e); // 是否包含某個元素 boolean contains(E e); // 總元素個數 int getSize(); // 集合是否爲空 boolean isEmpty(); }
3.基於二分搜索樹的集合segmentfault
關於二分搜索樹的底層實現,你們能夠去看個人另外一篇文章: BST
public class BSTSet<E extends Comparable<E>> implements Set<E> { private BST<E> bst; public BSTSet() { bst = new BST<>(); } @Override public void add(E e) { bst.add(e); } @Override public void remove(E e) { bst.remove(e); } @Override public boolean contains(E e) { return bst.contains(e); } @Override public int getSize() { return bst.getSize(); } @Override public boolean isEmpty() { return bst.isEmpty(); } }
4.基於鏈表的集合數組
關於鏈表的底層實現,你們能夠去看個人另外一篇文章: LinkedList
public class LinkedListSet<E> implements Set<E> { private LinkedList<E> list; public LinkedListSet() { list = new LinkedList<>(); } @Override public void add(E e) { if (!list.contains(e)) { list.addFirst(e); } } @Override public void remove(E e) { list.removeElement(e); } @Override public int getSize() { return list.getSize(); } @Override public boolean contains(E e) { return list.contains(e); } @Override public boolean isEmpty() { return list.isEmpty(); } }
5.BSTSet
和LinkedListSet
複雜度分析數據結構
\ | LinkedListSet | BSTSet |
---|---|---|
add | O(n) | O(h) |
contains | O(n) | O(h) |
remove | O(n) | O(h) |
注:h
爲二分搜索樹的高度,n
和h
是什麼關係呢?
假設二分搜索樹是一顆滿樹:
那麼:n = 2^0 + 2^1 + ... + 2^(h-1) = 2^h - 1
即:h = log2(n + 1)
由於這是咱們假設的一種狀況,真實狀況種可能二分搜索樹並非一顆滿樹,因此這是一個平均複雜度,又在複雜度分析中能夠不去考慮log
的底,因此LinkedListSet
和BSTSet
的複雜度以下:app
\ | LinkedListSet | BSTSet |
---|---|---|
add | O(n) | O(logn) 平均 |
contains | O(n) | O(logn) 平均 |
remove | O(n) | O(logn) 平均 |
6.LeetCode
中有關集合的問題
6.1 題目:
804. 惟一摩爾斯密碼詞
6.2 描述:ide
國際摩爾斯密碼定義一種標準編碼方式,將每一個字母對應於一個由一系列點和短線組成的字符串, 好比: "a" 對應 ".-", "b" 對應 "-...", "c" 對應 "-.-.", 等等。 爲了方便,全部26個英文字母對應摩爾斯密碼錶以下: [".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."] 給定一個單詞列表,每一個單詞能夠寫成每一個字母對應摩爾斯密碼的組合。例如,"cab" 能夠寫成 "-.-.-....-",(即 "-.-." + "-..." + ".-"字符串的結合)。咱們將這樣一個鏈接過程稱做單詞翻譯。 返回咱們能夠得到全部詞不一樣單詞翻譯的數量。
6.3例子:函數
例如: 輸入: words = ["gin", "zen", "gig", "msg"] 輸出: 2 解釋: 各單詞翻譯以下: "gin" -> "--...-." "zen" -> "--...-." "gig" -> "--...--." "msg" -> "--...--." 共有 2 種不一樣翻譯, "--...-." 和 "--...--.".
6.4解決代碼以下:ui
import java.util.TreeSet; class Solution { public int uniqueMorseRepresentations(String[] words) { // 摩斯密碼 String[] code = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}; TreeSet<String> set = new TreeSet<>(); for (String word : words) { // 每一個單詞的莫斯密碼 StringBuilder res = new StringBuilder(); for (int i = 0; i < word.length(); i++) { Character c = word.charAt(i); res.append(code[c - 'a']); } set.add(res.toString()); } return set.size(); } }
1.映射基礎:this
key
),尋找值(value
)2.映射接口
public interface Map<K, V> { // 添加鍵值對 void add(K key, V value); // 根據鍵,移除值 V remove(K key); // 是否包含某個鍵值對 boolean contains(K key); // 根據鍵,獲取值 V get(K key); // 設置鍵值對 void set(K key, V value); // 鍵值對個數 int getSize(); // map是否爲空 boolean isEmpty(); }
3.基於鏈表的映射
public class LinkedListMap<K, V> implements Map<K, V> { // 節點 private class Node { // 存儲key public K key; // 存儲的value public V value; // 下一個節點 public Node next; public Node(K key, V value, Node node) { this.key = key; this.value = value; this.next = node; } public Node(K key) { this(key, null, null); } public Node() { this(null, null, null); } @Override public String toString() { return key.toString() + ':' + value.toString(); } } private int size; private Node dummyHead; public LinkedListMap() { size = 0; dummyHead = new Node(); } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size == 0; } // 經過key獲取對應的node節點 private Node getNode(K key) { Node curNode = dummyHead.next; while (curNode != null) { if (curNode.key.equals(key)) { return curNode; } else { curNode = curNode.next; } } return null; } @Override public boolean contains(K key) { return getNode(key) != null; } @Override public V get(K key) { Node node = getNode(key); return node == null ? null : node.value; } @Override public void add(K key, V value) { Node node = getNode(key); if (node != null) { node.value = value; } else { dummyHead.next = new Node(key, value, dummyHead.next); size++; } } @Override public void set(K key, V value) { Node node = getNode(key); if (node == null) { throw new IllegalArgumentException(key + "is not exists"); } else { node.value = value; } } @Override public V remove(K key) { Node prev = dummyHead.next; while (prev != null) { if (prev.next.key.equals(key)) { break; } else { prev = prev.next; } } if (prev.next != null) { Node delNode = prev.next; prev.next = delNode.next; delNode.next = null; size--; return delNode.value; } return null; } }
4.基於二分搜索樹的映射
public class BSTMap<K extends Comparable<K>, V> implements Map<K, V> { // 節點 private class Node { public K key; public V value; public Node left; public Node right; public Node(K key, V value) { this.key = key; this.value = value; left = null; right = null; } } private int size; private Node root; public BSTMap() { size = 0; root = null; } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size == 0; } @Override public void add(K key, V value) { root = add(root, key, value); } // 向以node爲根的二分搜索樹中插入元素(key,value) private Node add(Node node, K key, V value) { if (node == null) { size++; return new Node(key, value); } if (node.key.compareTo(key) < 0) { node.right = add(node.right, key, value); } else if (node.key.compareTo(key) > 0) { node.left = add(node.left, key, value); } else { // node.key.compareTo(key) == 0 node.value = value; } return node; } // 返回以node爲根節點的二分搜索樹中指定key值的Node private Node getNode(Node node, K key) { if (node == null) { return null; } if (node.key.compareTo(key) == 0) { // 找到指定的節點 return node; } else if (node.key.compareTo(key) < 0) { return getNode(node.right, key); } else { // node.key.compareTo(key) > 0 return getNode(node.left, key); } } @Override public boolean contains(K key) { return getNode(root, key) != null; } @Override public V get(K key) { Node node = getNode(root, key); return node == null ? null : node.value; } @Override public void set(K key, V value) { Node node = getNode(root, key); if (node == null) { throw new IllegalArgumentException(key + "is not exists"); } node.value = value; } @Override public V remove(K key) { Node node = getNode(root, key); if (node != null) { root = remove(root, key); return node.value; } return null; } // 刪除二分搜索樹以node爲最小值的節點 // 返回刪除節點後的新的二分搜索樹的根 private Node removeMin(Node node) { // 找到須要刪除的節點 if (node.left == null) { Node rightNode = node.right; node.right = null; size--; return rightNode; } node.left = removeMin(node.left); return node; } // 返回以node爲根的二分搜索樹的最小值的節點 private Node minimum(Node node) { if (node.left == null) { return node; } return minimum(node.left); } private Node remove(Node node, K key) { if (node == null) { return null; } if (node.key.compareTo(key) > 0) { node.left = remove(node.left, key); return node; } else if (node.key.compareTo(key) < 0) { node.right = remove(node.right, key); return node; } else { // e == node.e if (node.left == null) { // 左子樹爲空 Node rightNode = node.right; node.right = null; size--; return rightNode; } if (node.right == null) { // 右子樹爲空 Node leftNode = node.left; node.left = null; size--; return leftNode; } // node的後繼 Node successor = minimum(node.right); // 把刪除node.right的後繼後的二叉樹賦值給後繼的right successor.right = removeMin(node.right); // 把node.left賦值給後繼的left successor.left = node.left; node.left = node.right = null; return successor; } } }
5.映射的複雜度分析
\ | LinkedListMap | BSTMap |
---|---|---|
add | O(n) | O(logn) 平均 |
remove | O(n) | O(logn) 平均 |
set | O(n) | O(logn) 平均 |
get | O(n) | O(logn) 平均 |
contains | O(n) | O(logn) 平均 |
從上面的代碼能夠看出,其實映射也是一個集合,只不過是攜帶了一個
value
而已,本質和集合沒有太大的區別。
349. 兩個數組的交集
題目地址:
349. 兩個數組的交集
描述:
給定兩個數組,編寫一個函數來計算它們的交集。
例子:
輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2]
代碼:
import java.util.ArrayList; import java.util.TreeSet; public class Solution { // 349. 兩個數組的交集 public int[] intersection(int[] nums1, int[] nums2) { TreeSet<Integer> set = new TreeSet<>(); for (int num : nums1) { set.add(num); } ArrayList<Integer> list = new ArrayList<>(); for (int num : nums2) { if (set.contains(num)) { list.add(num); set.remove(num); } } int[] arr = new int[list.size()]; for (int i = 0; i < list.size(); i++) { arr[i] = list.get(i); } return arr; } }
350. 兩個數組的交集 II
題目地址:
350. 兩個數組的交集 II
描述:
給定兩個數組,編寫一個函數來計算它們的交集。
例子:
輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2,2]
代碼:
import java.util.ArrayList; import java.util.TreeMap; public class Solution { // 350. 兩個數組的交集 II public int[] intersect(int[] nums1, int[] nums2) { TreeMap<Integer, Integer> map = new TreeMap<>(); for (int num : nums1) { if (map.containsKey(num)) { map.put(num, map.get(num) + 1); } else { map.put(num, 1); } } ArrayList<Integer> list = new ArrayList<Integer>(); for (int num : nums2) { if (map.containsKey(num)) { list.add(num); int count = map.get(num); map.put(num, --count); if (count == 0) { map.remove(num); } } } int[] arr = new int[list.size()]; for (int i = 0; i < list.size(); i++) { arr[i] = list.get(i); } return arr; } }