1. 程式人生 > >LeetCode676. Implement Magic Dictionary & 295. Find Median from Data Stream

LeetCode676. Implement Magic Dictionary & 295. Find Median from Data Stream

LeetCode676. Implement Magic Dictionary & 295. Find Median from Data Stream


LeetCode-676. Implement Magic Dictionary

題目連結

題目

在這裡插入圖片描述

解析

兩種解法: 模糊搜尋和利用字典樹。

模糊搜尋:

buildDict過程:

  • 準備一個HashMap<String, HashSet<Character>>
    key存字串,val存的是字元的集合;
  • 其中key是在列舉每一個字串的每一個位置,去掉原來的那個字元,然後用一個特殊字元加入進去,並把替換的字元加入val中的set集合。

search過程:

  • 檢視在替換任意一個字元,之後的集合,且這個集合中不能包含替換的字元,或者可以包含但是set.size() > 1也行。

在這裡插入圖片描述

class MagicDictionary {

    private HashMap<String, HashSet<Character>>magicMap;

    /** Initialize your data structure here. */
public MagicDictionary() { magicMap = new HashMap<>(); } /** Build a dictionary through a list of words */ public void buildDict(String[] dict) { for(int i = 0; i < dict.length; i++){ for(int j = 0; j < dict[i].length(); j++){ String key =
dict[i].substring(0, j) + "*" + dict[i].substring(j+1, dict[i].length()); HashSet<Character>valSet = magicMap.get(key); if(valSet == null) valSet = new HashSet<>(); valSet.add(dict[i].charAt(j)); magicMap.put(key, valSet); } } } /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */ public boolean search(String word) { for(int i = 0; i < word.length(); i++){ String key = word.substring(0, i) + "*" + word.substring(i+1, word.length()); HashSet<Character>valSet = magicMap.get(key); if(valSet == null) continue; // 只要有一個滿足這種情況就可以了 注意第二種情況,例如查詢 hello,之前map裡如果有hello, hallo (valSet.size() > 1)也是可以的 if(!valSet.contains(word.charAt(i)) || valSet.size() > 1) return true; } return false; } }

字典樹寫法

字典樹基礎可以看這裡

插入沒什麼好說的,建立字典樹即可,search的過程要維護一個isOneDiff變數。表示的是當前是否已經有一個不同了。然後dfs即可。

class MagicDictionary {

    private class Node{
        public boolean end;
        public Node[] nexts;
        public Node() {
            end = false;
            this.nexts = new Node[26];
        }
    }

    private class Trie{

        private Node root;

        public Trie() {
            this.root = new Node();
        }

        public void insert(String word){
            Node cur = root;
            for(int i = 0; i < word.length(); i++){
                int index = word.charAt(i) - 'a';
                if(cur.nexts[index] == null)
                    cur.nexts[index] = new Node();
                cur = cur.nexts[index];
            }
            cur.end = true;
        }
    }

    private Trie trie;

    public MagicDictionary() {
        trie = new Trie();
    }

    public void buildDict(String[] dict) {
        for(int i = 0; i < dict.length; i++)
            trie.insert(dict[i]);
    }

    public boolean search(String word) {
        return rec(trie.root, word,  0, false);
    }

    public boolean rec(Node node, String word, int i, boolean isOneDiff){
        if(i == word.length() && node.end && isOneDiff)
            return true;
        else if(i == word.length())
            return false;
        int index = word.charAt(i) - 'a';
        for(int k = 0; k < 26; k++){
            if(node.nexts[k] == null)
                continue;
            if(k == index && !isOneDiff){
                if(rec(node.nexts[k], word, i+1, false))
                    return true;
            } else if(k == index && isOneDiff){
                if(rec(node.nexts[k], word, i+1, true))
                    return true;
            }else if(k != index && !isOneDiff){
                if(rec(node.nexts[k], word, i+1, true))
                    return true;
            }
            // k!=index && isOneDiff shouldn't be consider
        }
        return false;
    }
}

LeetCode-295. Find Median from Data Stream

題目連結

題目

在這裡插入圖片描述

解析

準備兩個堆: 一個最大堆(maxHeap),一個最小堆minHeap

  • 最大堆儲存較小元素的一半,最大堆儲存較大元素的一半;
  • 新增元素後,始終要維持要麼兩個堆的元素相等,要麼左邊的堆(maxHeap)元素比右邊多一個;
  • 如果不是上面兩種情況,就要在新增元素之後維護;
  • findMedian函式: 查詢時,如果兩個堆的元素個數相等就返回兩個堆頂的元素的和除以一半,否則返回maxHeap.peek()

看一個例子:

num smaller(maxHeap) bigger(minHeap) median
5 5 5.0
8 5 8 6.5
2 [2、5] 8 5
11 [2、5] [8、11] 6.5
3 [2、3、5] [8、11] 5
4 [2、3、4、5] [8、11] 先調整
[2、3、4] [5、8、11] 4.5
14 [2、3、4] [5、8、11、14] 先調整
[2、3、4、5] [8、11、14] 5
class MedianFinder {

    private PriorityQueue<Integer>maxHeap; // 第一個(更小的)是最大堆 (左邊的)
    private PriorityQueue<Integer>minHeap; // 第二個(更大的)是最小堆 (右邊的)
   
    public MedianFinder() {
        maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
        minHeap = new PriorityQueue<>(); // java預設是最小堆 (堆頂最小)
    }

    public void addNum(int num) {
        if(maxHeap.isEmpty() || (!maxHeap.isEmpty() && num <= maxHeap.peek()))
            maxHeap.add(num);
        else
            minHeap.add(num);

        if(maxHeap.size() < minHeap.size())
            maxHeap.add(minHeap.poll());
        else if(maxHeap.size() - minHeap.size() == 2)
            minHeap.add(maxHeap.poll());
    }

    public double findMedian() {
        if(maxHeap.size() == minHeap.size())
            return (maxHeap.peek() + minHeap.peek())/2.0;
        else    // minHeap.size() = maxHeap.size() + 1;
            return maxHeap.peek();
    }
}