摘要:為了方便,所有個(gè)英文字母對(duì)應(yīng)摩爾斯密碼表如下給定一個(gè)單詞列表,每個(gè)單詞可以寫(xiě)成每個(gè)字母對(duì)應(yīng)摩爾斯密碼的組合。例如,可以寫(xiě)成,即字符串的結(jié)合。我們將這樣一個(gè)連接過(guò)程稱作單詞翻譯。返回我們可以獲得所有詞不同單詞翻譯的數(shù)量。
我理解的數(shù)據(jù)結(jié)構(gòu)(六)—— 集合和映射(Set And Map) 一、集合
1.典型應(yīng)用場(chǎng)景
客戶統(tǒng)計(jì)
詞匯量統(tǒng)計(jì)
2.集合接口
public interface Set{ // 集合不存放相同元素 void add(E e); // 刪除元素 void remove(E e); // 是否包含某個(gè)元素 boolean contains(E e); // 總元素個(gè)數(shù) int getSize(); // 集合是否為空 boolean isEmpty(); }
3.基于二分搜索樹(shù)的集合
關(guān)于二分搜索樹(shù)的底層實(shí)現(xiàn),大家可以去看我的另一篇文章:BST
public class BSTSet> implements Set { private BST 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.基于鏈表的集合
關(guān)于鏈表的底層實(shí)現(xiàn),大家可以去看我的另一篇文章:LinkedList
public class LinkedListSetimplements Set { private LinkedList 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復(fù)雜度分析
LinkedListSet | BSTSet | |
---|---|---|
add | O(n) | O(h) |
contains | O(n) | O(h) |
remove | O(n) | O(h) |
注:h為二分搜索樹(shù)的高度,n和h是什么關(guān)系呢?
假設(shè)二分搜索樹(shù)是一顆滿樹(shù):
那么:n = 2^0 + 2^1 + ... + 2^(h-1) = 2^h - 1
即:h = log2(n + 1)
因?yàn)檫@是我們假設(shè)的一種情況,真實(shí)情況種可能二分搜索樹(shù)并不是一顆滿樹(shù),所以這是一個(gè)平均復(fù)雜度,又在復(fù)雜度分析中可以不去考慮log的底,所以LinkedListSet和BSTSet的復(fù)雜度如下:
LinkedListSet | BSTSet | |
---|---|---|
add | O(n) | O(logn) 平均 |
contains | O(n) | O(logn) 平均 |
remove | O(n) | O(logn) 平均 |
6.LeetCode中有關(guān)集合的問(wèn)題
6.1 題目:
804. 唯一摩爾斯密碼詞
6.2 描述:
國(guó)際摩爾斯密碼定義一種標(biāo)準(zhǔn)編碼方式,將每個(gè)字母對(duì)應(yīng)于一個(gè)由一系列點(diǎn)和短線組成的字符串, 比如: "a" 對(duì)應(yīng) ".-", "b" 對(duì)應(yīng) "-...", "c" 對(duì)應(yīng) "-.-.", 等等。 為了方便,所有26個(gè)英文字母對(duì)應(yīng)摩爾斯密碼表如下: [".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."] 給定一個(gè)單詞列表,每個(gè)單詞可以寫(xiě)成每個(gè)字母對(duì)應(yīng)摩爾斯密碼的組合。例如,"cab" 可以寫(xiě)成 "-.-.-....-",(即 "-.-." + "-..." + ".-"字符串的結(jié)合)。我們將這樣一個(gè)連接過(guò)程稱作單詞翻譯。 返回我們可以獲得所有詞不同單詞翻譯的數(shù)量。
6.3例子:
例如: 輸入: words = ["gin", "zen", "gig", "msg"] 輸出: 2 解釋: 各單詞翻譯如下: "gin" -> "--...-." "zen" -> "--...-." "gig" -> "--...--." "msg" -> "--...--." 共有 2 種不同翻譯, "--...-." 和 "--...--.".
6.4解決代碼如下:
import java.util.TreeSet; class Solution { public int uniqueMorseRepresentations(String[] words) { // 摩斯密碼 String[] code = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}; TreeSet二、映射set = new TreeSet<>(); for (String word : words) { // 每個(gè)單詞的莫斯密碼 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.映射基礎(chǔ):
存儲(chǔ)(鍵、值)數(shù)據(jù)對(duì)的數(shù)據(jù)結(jié)構(gòu)(key、value)
根據(jù)鍵(key),尋找值(value)
2.映射接口
public interface Map{ // 添加鍵值對(duì) void add(K key, V value); // 根據(jù)鍵,移除值 V remove(K key); // 是否包含某個(gè)鍵值對(duì) boolean contains(K key); // 根據(jù)鍵,獲取值 V get(K key); // 設(shè)置鍵值對(duì) void set(K key, V value); // 鍵值對(duì)個(gè)數(shù) int getSize(); // map是否為空 boolean isEmpty(); }
3.基于鏈表的映射
public class LinkedListMapimplements Map { // 節(jié)點(diǎn) private class Node { // 存儲(chǔ)key public K key; // 存儲(chǔ)的value public V value; // 下一個(gè)節(jié)點(diǎn) 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; } // 通過(guò)key獲取對(duì)應(yīng)的node節(jié)點(diǎn) 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.基于二分搜索樹(shù)的映射
public class BSTMap, V> implements Map { // 節(jié)點(diǎn) 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為根的二分搜索樹(shù)中插入元素(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為根節(jié)點(diǎn)的二分搜索樹(shù)中指定key值的Node private Node getNode(Node node, K key) { if (node == null) { return null; } if (node.key.compareTo(key) == 0) { // 找到指定的節(jié)點(diǎn) 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; } // 刪除二分搜索樹(shù)以node為最小值的節(jié)點(diǎn) // 返回刪除節(jié)點(diǎn)后的新的二分搜索樹(shù)的根 private Node removeMin(Node node) { // 找到需要?jiǎng)h除的節(jié)點(diǎn) if (node.left == null) { Node rightNode = node.right; node.right = null; size--; return rightNode; } node.left = removeMin(node.left); return node; } // 返回以node為根的二分搜索樹(shù)的最小值的節(jié)點(diǎn) 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) { // 左子樹(shù)為空 Node rightNode = node.right; node.right = null; size--; return rightNode; } if (node.right == null) { // 右子樹(shù)為空 Node leftNode = node.left; node.left = null; size--; return leftNode; } // node的后繼 Node successor = minimum(node.right); // 把刪除node.right的后繼后的二叉樹(shù)賦值給后繼的right successor.right = removeMin(node.right); // 把node.left賦值給后繼的left successor.left = node.left; node.left = node.right = null; return successor; } } }
5.映射的復(fù)雜度分析
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) 平均 |
從上面的代碼可以看出,其實(shí)映射也是一個(gè)集合,只不過(guò)是攜帶了一個(gè)value而已,本質(zhì)和集合沒(méi)有太大的區(qū)別。四、兩個(gè)LeetCode上集合和映射的問(wèn)題
349. 兩個(gè)數(shù)組的交集
題目地址:
349. 兩個(gè)數(shù)組的交集
描述:
給定兩個(gè)數(shù)組,編寫(xiě)一個(gè)函數(shù)來(lái)計(jì)算它們的交集。
例子:
輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2]
代碼:
import java.util.ArrayList; import java.util.TreeSet; public class Solution { // 349. 兩個(gè)數(shù)組的交集 public int[] intersection(int[] nums1, int[] nums2) { TreeSetset = new TreeSet<>(); for (int num : nums1) { set.add(num); } ArrayList 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. 兩個(gè)數(shù)組的交集 II
題目地址:
350. 兩個(gè)數(shù)組的交集 II
描述:
給定兩個(gè)數(shù)組,編寫(xiě)一個(gè)函數(shù)來(lái)計(jì)算它們的交集。
例子:
輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2,2]
代碼:
import java.util.ArrayList; import java.util.TreeMap; public class Solution { // 350. 兩個(gè)數(shù)組的交集 II public int[] intersect(int[] nums1, int[] nums2) { TreeMapmap = new TreeMap<>(); for (int num : nums1) { if (map.containsKey(num)) { map.put(num, map.get(num) + 1); } else { map.put(num, 1); } } ArrayList list = new ArrayList (); 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; } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29523.html
摘要:為了方便,所有個(gè)英文字母對(duì)應(yīng)摩爾斯密碼表如下給定一個(gè)單詞列表,每個(gè)單詞可以寫(xiě)成每個(gè)字母對(duì)應(yīng)摩爾斯密碼的組合。例如,可以寫(xiě)成,即字符串的結(jié)合。我們將這樣一個(gè)連接過(guò)程稱作單詞翻譯。返回我們可以獲得所有詞不同單詞翻譯的數(shù)量。 我理解的數(shù)據(jù)結(jié)構(gòu)(六)—— 集合和映射(Set And Map) 一、集合 1.典型應(yīng)用場(chǎng)景 客戶統(tǒng)計(jì) 詞匯量統(tǒng)計(jì) 2.集合接口 public interface ...
摘要:初始化申明一個(gè)設(shè)置和獲取值使用設(shè)置新值或更新值申明設(shè)置值張三豐張三豐重復(fù)設(shè)置值如果鍵值存在則新值替換舊值張三豐使用獲取值,如果獲取的不存在返回分別獲取判斷是否存在使用判斷給定是否存在映射內(nèi)。 本文同步帶你入門(mén) 帶你玩轉(zhuǎn) JavaScript ES6 (六) - Map 映射,轉(zhuǎn)載請(qǐng)注明出處。 本章我們講學(xué)習(xí) ES6 中的 Map(映射)。上一章節(jié)我們學(xué)習(xí)了 [Set(集合)]()的相關(guān)...
摘要:在編程文化中,我們有一個(gè)名為面向?qū)ο缶幊痰臇|西,這是一組技術(shù),使用對(duì)象和相關(guān)概念作為程序組織的中心原則。這是構(gòu)造器函數(shù)的作用。因此,上面的類(lèi)聲明等同于上一節(jié)中的構(gòu)造器定義。 來(lái)源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:The Secret Life of Objects 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考...
摘要:從數(shù)組索引為開(kāi)始刪除元素,直到對(duì)數(shù)組元素運(yùn)用指定方法為為止。對(duì)兩個(gè)數(shù)組的元素分別調(diào)用指定方法后,返回以運(yùn)行結(jié)果為判定基準(zhǔn)的并集,并集是原始數(shù)組元素的并集而不是運(yùn)行結(jié)果的并集。 原文地址:JavaScript30秒, 從入門(mén)到放棄之Array(六)博客地址:JavaScript30秒, 從入門(mén)到放棄之Array(六) 水平有限,歡迎批評(píng)指正 tail Returns all elem...
摘要:二求文件中包含包租婆的行數(shù)從一個(gè)總計(jì)行的文件中找出所有包含包租婆的行數(shù),我們不用太動(dòng)腦筋就有一個(gè)算法讀一行,判斷這一行有包租婆嗎如果有,全局變量加。在臺(tái)機(jī)器上分別執(zhí)行笨辦法計(jì)算包含包租婆的行數(shù)。 一、搬磚 vs. 分布式計(jì)算 一個(gè)人搬磚很累,幾個(gè)人一起搬就會(huì)輕松很多,也會(huì)快很多: showImg(https://segmentfault.com/img/bVp6EK); 分布并行計(jì)算和...
閱讀 4173·2021-09-22 15:34
閱讀 2783·2021-09-22 15:29
閱讀 503·2019-08-29 13:52
閱讀 3362·2019-08-29 11:30
閱讀 2274·2019-08-26 10:40
閱讀 847·2019-08-26 10:19
閱讀 2268·2019-08-23 18:16
閱讀 2331·2019-08-23 17:50