From 3f2aab09248edaae39511369646faaef03922a09 Mon Sep 17 00:00:00 2001 From: fanlu91 Date: Sun, 12 May 2019 23:01:53 +0800 Subject: [PATCH 1/5] week 4 homework id 26 --- Week_04/id_26/Leetcode_211_26.java | 108 +++++++++++++++++++++++++++++ Week_04/id_26/Leetcode_720_26.java | 67 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 Week_04/id_26/Leetcode_211_26.java create mode 100644 Week_04/id_26/Leetcode_720_26.java diff --git a/Week_04/id_26/Leetcode_211_26.java b/Week_04/id_26/Leetcode_211_26.java new file mode 100644 index 00000000..2ec61528 --- /dev/null +++ b/Week_04/id_26/Leetcode_211_26.java @@ -0,0 +1,108 @@ +package com.fanlu.leetcode.trietree; + +// Source : https://leetcode.com/problems/add-and-search-word-data-structure-design/ +// Id : 211 +// Author : Fanlu Hai +// Date : 2018-05-12 +// Other : +// Tips : + +public class WordDictionary { + private Trie trie; + + /** + * Initialize your data structure here. + */ + public WordDictionary() { + trie = new Trie(); + } + + /** + * Adds a word into the data structure. + */ + public void addWord(String word) { + trie.insert(word); + } + + /** + * Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. + */ + public boolean search(String word) { + return trie.search(word); + } + + private class Trie { + private class Node { + private boolean isWordEnd; + private Node[] next; + + public Node() { + this(false); + } + + ; + + public Node(boolean isWordEnd) { + this.isWordEnd = isWordEnd; + this.next = new Node[26]; + } + } + + private Node root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new Node(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + int wordLen = word.length(); + Node cur = root; + for (int i = 0; i < wordLen; ++i) { + char ch = word.charAt(i); + if (cur.next[ch - 'a'] == null) + cur.next[ch - 'a'] = new Node(); + cur = cur.next[ch - 'a']; + } + + if (!cur.isWordEnd) { + cur.isWordEnd = true; + } + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + return search(root, word, 0); + } + + private boolean search(Node node, String word, int index) { + if (index == word.length()) { + return node.isWordEnd; + } + + char ch = word.charAt(index); + index += 1; + if (ch == '.') { + for (int i = 0; i < 26; ++i) { + if (node.next[i] == null) continue; + boolean result = search(node.next[i], word, index); + if (result == true) return true; + } + return false; + } else { + // current character matched ? + boolean curIs = node.next[ch - 'a'] != null; + return curIs ? search(node.next[ch - 'a'], word, index) : false; + } + } + } + + +} diff --git a/Week_04/id_26/Leetcode_720_26.java b/Week_04/id_26/Leetcode_720_26.java new file mode 100644 index 00000000..3c231e1d --- /dev/null +++ b/Week_04/id_26/Leetcode_720_26.java @@ -0,0 +1,67 @@ +package com.fanlu.leetcode.trietree; + +import java.util.ArrayDeque; +import java.util.Deque; + +// Source : https://leetcode.com/problems/longest-word-in-dictionary/ +// Id : 720 +// Author : Fanlu Hai +// Date : 2018-05-12 +// Other : +// Tips : +public class LongestWordInDictionary { + TrieNode root = new TrieNode("/"); +// String longest = null; + + public void insert(String string) { + TrieNode node = root; + for (int i = 0; i < string.length(); i++) { + int index = string.charAt(i) - 'a'; + if (null == node.children[index]) { + node.children[index] = new TrieNode(); + } + node = node.children[index]; + } + node.isWord = true; + node.word = string; + } + + public String longestWord(String[] words) { + for (String word : words) { + insert(word); + } + Deque st = new ArrayDeque<>(); + st.push(root); + String best = ""; + + while (!st.isEmpty()) { + TrieNode nd = st.pop(); + if (nd.word != null && nd.word.length() > best.length()) + best = nd.word; + if (null == nd.children) + continue; + for (char c = 'z'; c != 'a' - 1; --c) { + TrieNode ch = nd.children[c - 'a']; + if (null == ch || ch.word == null) + continue; + st.push(ch); + } + } + return best; + } + + public class TrieNode { + public String word; + public TrieNode[] children = new TrieNode[26]; + public boolean isWord = false; + + public TrieNode(String word) { + this.word = word; + } + + public TrieNode() { + + } + + } +} From c178caf70b27d8665a920fc32b9b47057b7326f0 Mon Sep 17 00:00:00 2001 From: fanlu91 Date: Wed, 15 May 2019 21:13:42 +0800 Subject: [PATCH 2/5] update solution --- Week_04/id_26/Leetcode_720_26.java | 109 ++++++++++++++++++----------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/Week_04/id_26/Leetcode_720_26.java b/Week_04/id_26/Leetcode_720_26.java index 3c231e1d..11213d53 100644 --- a/Week_04/id_26/Leetcode_720_26.java +++ b/Week_04/id_26/Leetcode_720_26.java @@ -1,67 +1,98 @@ package com.fanlu.leetcode.trietree; -import java.util.ArrayDeque; -import java.util.Deque; +import java.util.HashMap; +import java.util.Stack; // Source : https://leetcode.com/problems/longest-word-in-dictionary/ // Id : 720 // Author : Fanlu Hai // Date : 2018-05-12 -// Other : +// Other : children list will affect the performance // Tips : public class LongestWordInDictionary { - TrieNode root = new TrieNode("/"); -// String longest = null; + TrieNode root = new TrieNode('/'); + String longest = ""; - public void insert(String string) { + public void insert(String string, int index) { TrieNode node = root; - for (int i = 0; i < string.length(); i++) { - int index = string.charAt(i) - 'a'; - if (null == node.children[index]) { - node.children[index] = new TrieNode(); - } - node = node.children[index]; + for (char c : string.toCharArray()) { + node.children.putIfAbsent(c, new TrieNode(c)); + node = node.children.get(c); } - node.isWord = true; - node.word = string; + // not only means this node is the end of a word,but also contains index information for this word. + node.index = index; } - public String longestWord(String[] words) { - for (String word : words) { - insert(word); + // 34.81%(22 ms) 97.45% + public String longestWordSlow(String[] words) { + for (int i = 0; i < words.length; i++) { + insert(words[i], i); + // System.out.println("insert: " + i + " " + words[i]); } - Deque st = new ArrayDeque<>(); - st.push(root); - String best = ""; - while (!st.isEmpty()) { - TrieNode nd = st.pop(); - if (nd.word != null && nd.word.length() > best.length()) - best = nd.word; - if (null == nd.children) - continue; - for (char c = 'z'; c != 'a' - 1; --c) { - TrieNode ch = nd.children[c - 'a']; - if (null == ch || ch.word == null) - continue; - st.push(ch); + Stack stack = new Stack(); + stack.addAll(root.children.values()); + + TrieNode node; + while (!stack.isEmpty()) { + node = stack.pop(); + // System.out.println(node.c+" "+node.index); + if (node.index != -1) { + String tmp = words[node.index]; + // System.out.println("check "+tmp); + if (tmp.length() > longest.length() + || (tmp.length() == longest.length() && tmp.compareTo(longest) < 0)) { + // System.out.println("longest "+tmp); + longest = tmp; + } + stack.addAll(node.children.values()); } + } - return best; + + return longest; } - public class TrieNode { - public String word; - public TrieNode[] children = new TrieNode[26]; - public boolean isWord = false; + //51.26% (16 ms) 98.36% + public String longestWord(String[] words) { + for (int i = 0; i < words.length; i++) { + insert(words[i], i); + // System.out.println("insert: " + i + " " + words[i]); + } + for (TrieNode child : root.children.values()) { + searchLongest(child, words); + } + return longest; + } - public TrieNode(String word) { - this.word = word; + public void searchLongest(TrieNode node, String[] words) { + if (node.index != -1) { + String tmp = words[node.index]; + // System.out.println("check "+tmp); + if (tmp.length() > longest.length() + || (tmp.length() == longest.length() && tmp.compareTo(longest) < 0)) { + // System.out.println("longest "+tmp); + longest = tmp; + } + for (TrieNode child : node.children.values()) { + searchLongest(child, words); + } } + } - public TrieNode() { + class TrieNode { + public char c; + // to keep track which word's insertion created this node + public int index = -1; + HashMap children = new HashMap(); + public TrieNode(char c) { + this.c = c; } + public TrieNode(char c, int index) { + this.c = c; + this.index = index; + } } } From 1c8cf5d1186d0eb2799a2bd5d7f487376c70bb92 Mon Sep 17 00:00:00 2001 From: fanlu91 Date: Thu, 16 May 2019 10:42:13 +0800 Subject: [PATCH 3/5] best solution for 720 --- Week_04/id_26/Leetcode_720_26.java | 114 ++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/Week_04/id_26/Leetcode_720_26.java b/Week_04/id_26/Leetcode_720_26.java index 11213d53..45428c29 100644 --- a/Week_04/id_26/Leetcode_720_26.java +++ b/Week_04/id_26/Leetcode_720_26.java @@ -7,33 +7,25 @@ // Id : 720 // Author : Fanlu Hai // Date : 2018-05-12 -// Other : children list will affect the performance -// Tips : +// Other : data structure of the children list will affect the performance significantly +// Tips : good test case ["gbra","jy","pl","zn","gb","j","jyh","jyhm","plr","znicn","p","gbr","zni","znic","aq"] public class LongestWordInDictionary { - TrieNode root = new TrieNode('/'); + TrieNodeUsingMap rootNodeUsingMap = new TrieNodeUsingMap('/'); + TrieNodeUsingArray rootNodeUsingArray = new TrieNodeUsingArray('/'); String longest = ""; - public void insert(String string, int index) { - TrieNode node = root; - for (char c : string.toCharArray()) { - node.children.putIfAbsent(c, new TrieNode(c)); - node = node.children.get(c); - } - // not only means this node is the end of a word,but also contains index information for this word. - node.index = index; - } // 34.81%(22 ms) 97.45% public String longestWordSlow(String[] words) { for (int i = 0; i < words.length; i++) { - insert(words[i], i); - // System.out.println("insert: " + i + " " + words[i]); + insertUsingMap(words[i], i); + // System.out.println("insertUsingMap: " + i + " " + words[i]); } - Stack stack = new Stack(); - stack.addAll(root.children.values()); + Stack stack = new Stack(); + stack.addAll(rootNodeUsingMap.children.values()); - TrieNode node; + TrieNodeUsingMap node; while (!stack.isEmpty()) { node = stack.pop(); // System.out.println(node.c+" "+node.index); @@ -54,18 +46,18 @@ public String longestWordSlow(String[] words) { } //51.26% (16 ms) 98.36% - public String longestWord(String[] words) { + public String longestWordBetter(String[] words) { for (int i = 0; i < words.length; i++) { - insert(words[i], i); - // System.out.println("insert: " + i + " " + words[i]); + insertUsingMap(words[i], i); + // System.out.println("insertUsingMap: " + i + " " + words[i]); } - for (TrieNode child : root.children.values()) { + for (TrieNodeUsingMap child : rootNodeUsingMap.children.values()) { searchLongest(child, words); } return longest; } - public void searchLongest(TrieNode node, String[] words) { + public void searchLongest(TrieNodeUsingMap node, String[] words) { if (node.index != -1) { String tmp = words[node.index]; // System.out.println("check "+tmp); @@ -74,25 +66,93 @@ public void searchLongest(TrieNode node, String[] words) { // System.out.println("longest "+tmp); longest = tmp; } - for (TrieNode child : node.children.values()) { + for (TrieNodeUsingMap child : node.children.values()) { searchLongest(child, words); } } } - class TrieNode { + //97.79% (6 ms) 97.18% (37.6 MB) + public String longestWord(String[] words) { + for (int i = 0; i < words.length; i++) { + insertUsingArray(words[i], i); + System.out.println("insert: " + i + " " + words[i]); + } + for (TrieNodeUsingArray child : rootNodeUsingArray.children) { + if (null != child) + searchLongest2(child, words); + } + return longest; + } + + public void searchLongest2(TrieNodeUsingArray node, String[] words) { + + if (node.index != -1) { + String tmp = words[node.index]; + // System.out.println("check "+tmp); + if (tmp.length() > longest.length() + || (tmp.length() == longest.length() && tmp.compareTo(longest) < 0)) { + System.out.println("longest " + tmp); + longest = tmp; + } + for (TrieNodeUsingArray child : node.children) { + if (null != child) + searchLongest2(child, words); + } + } + } + + class TrieNodeUsingMap { public char c; // to keep track which word's insertion created this node public int index = -1; - HashMap children = new HashMap(); + HashMap children = new HashMap(); - public TrieNode(char c) { + public TrieNodeUsingMap(char c) { this.c = c; } - public TrieNode(char c, int index) { + public TrieNodeUsingMap(char c, int index) { this.c = c; this.index = index; } } + + public void insertUsingMap(String string, int index) { + TrieNodeUsingMap node = rootNodeUsingMap; + for (char c : string.toCharArray()) { + node.children.putIfAbsent(c, new TrieNodeUsingMap(c)); + node = node.children.get(c); + } + // not only means this node is the end of a word,but also contains index information for this word. + node.index = index; + } + + class TrieNodeUsingArray { + public char c; + // to keep track which word's insertion created this node + public int index = -1; + TrieNodeUsingArray[] children = new TrieNodeUsingArray[26]; + + public TrieNodeUsingArray(char c) { + this.c = c; + } + + public TrieNodeUsingArray(char c, int index) { + this.c = c; + this.index = index; + } + } + + public void insertUsingArray(String string, int index) { + TrieNodeUsingArray node = rootNodeUsingArray; + for (char c : string.toCharArray()) { + int n = c - 'a'; + if (node.children[n] == null) { + node.children[n] = new TrieNodeUsingArray(c); + } + node = node.children[n]; + } + node.index = index; + } } From 7a6347e66e6f06b3c9903491afe3f2f79f55fa69 Mon Sep 17 00:00:00 2001 From: fanlu91 Date: Fri, 17 May 2019 15:36:16 +0800 Subject: [PATCH 4/5] best solution for 211 --- Week_04/id_26/Leetcode_211_26.java | 129 ++++++++++++++--------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/Week_04/id_26/Leetcode_211_26.java b/Week_04/id_26/Leetcode_211_26.java index 2ec61528..266e88dc 100644 --- a/Week_04/id_26/Leetcode_211_26.java +++ b/Week_04/id_26/Leetcode_211_26.java @@ -8,101 +8,96 @@ // Tips : public class WordDictionary { - private Trie trie; + TrieNode root; /** * Initialize your data structure here. */ public WordDictionary() { - trie = new Trie(); + root = new TrieNode(); } /** * Adds a word into the data structure. */ public void addWord(String word) { - trie.insert(word); + TrieNode node = root; + for (char c : word.toCharArray()) { + int index = c - 'a'; + if (node.children[index] == null) { + node.children[index] = new TrieNode(); + } + node = node.children[index]; + } + node.isEndOfAWord = true; } /** * Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ + // 100.00% 76.32% (54.9) public boolean search(String word) { - return trie.search(word); + return search(root, word, 0); } - private class Trie { - private class Node { - private boolean isWordEnd; - private Node[] next; - - public Node() { - this(false); - } - - ; - - public Node(boolean isWordEnd) { - this.isWordEnd = isWordEnd; - this.next = new Node[26]; - } + // compare each node's children with the char at the given index of the word incrementally + public boolean search(TrieNode node, String word, int index) { + // if index is already longer than max index (length-1) + // then check if the node is the end of an work, there's no need to check its children + if (index == word.length()) { + return node.isEndOfAWord; } - private Node root; - - /** - * Initialize your data structure here. - */ - public Trie() { - root = new Node(); - } + char ch = word.charAt(index); + index++; - /** - * Inserts a word into the trie. - */ - public void insert(String word) { - int wordLen = word.length(); - Node cur = root; - for (int i = 0; i < wordLen; ++i) { - char ch = word.charAt(i); - if (cur.next[ch - 'a'] == null) - cur.next[ch - 'a'] = new Node(); - cur = cur.next[ch - 'a']; + if (ch == '.') { + for (TrieNode child : node.children) { + if (child != null) { + // if this child works then return true + if (search(child, word, index)) { + return true; + } + } } - - if (!cur.isWordEnd) { - cur.isWordEnd = true; + // no child's path works. + return false; + } else { + if (node.children[ch - 'a'] != null) { + return search(node.children[ch - 'a'], word, index); + } else { + return false; } } + } - /** - * Returns if the word is in the trie. - */ - public boolean search(String word) { - return search(root, word, 0); - } + class TrieNode { + public TrieNode[] children = new TrieNode[26]; + public boolean isEndOfAWord = false; - private boolean search(Node node, String word, int index) { - if (index == word.length()) { - return node.isWordEnd; - } + } - char ch = word.charAt(index); - index += 1; - if (ch == '.') { - for (int i = 0; i < 26; ++i) { - if (node.next[i] == null) continue; - boolean result = search(node.next[i], word, index); - if (result == true) return true; - } - return false; - } else { - // current character matched ? - boolean curIs = node.next[ch - 'a'] != null; - return curIs ? search(node.next[ch - 'a'], word, index) : false; - } - } + public static void main(String[] args) { + WordDictionary obj = new WordDictionary(); +// obj.addWord("at"); + obj.addWord("and"); +// obj.addWord("an"); + obj.addWord("add"); +// obj.addWord("a"); + System.out.println(obj.search(".ad")); + System.out.println(obj.search("a.d")); + System.out.println(obj.search("b.")); + System.out.println(obj.search("....")); + System.out.println(obj.search("..")); + System.out.println(obj.search("a.d.")); + System.out.println(obj.search(".ad")); } +} -} +/** + * Your WordDictionary object will be instantiated and called as such: + * WordDictionary obj = new WordDictionary(); + * obj.addWord(word); + * boolean param_2 = obj.search(word); + */ \ No newline at end of file From f502f96e34cb03b838f05c0d491747d2354063d6 Mon Sep 17 00:00:00 2001 From: fanlu91 Date: Fri, 24 May 2019 17:39:09 +0800 Subject: [PATCH 5/5] best solution for 169 241 --- Week_04/id_26/Leetcode_169_26.java | 62 +++++++++++++++++ Week_04/id_26/Leetcode_241_26.java | 106 +++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 Week_04/id_26/Leetcode_169_26.java create mode 100644 Week_04/id_26/Leetcode_241_26.java diff --git a/Week_04/id_26/Leetcode_169_26.java b/Week_04/id_26/Leetcode_169_26.java new file mode 100644 index 00000000..9368c342 --- /dev/null +++ b/Week_04/id_26/Leetcode_169_26.java @@ -0,0 +1,62 @@ +package divideandconquer; + +import java.util.HashMap; +import java.util.Map; + +// Source : https://leetcode.com/problems/majority-element/ +// Id : 169 +// Author : Fanlu Hai +// Date : 2018-05-24 +// Other : +// Tips : boyer moore voting algorithm; +// take full advantage of the situation to get the best solution. + +public class MajorityElement { + // straight forward way is to store appearance of number in a hashmap + // 16.69% 16 ms 99.07% 39.1 MB + public int majorityElementSlow(int[] nums) { +// System.out.println(nums.length / 2 + 1); + Map counter = new HashMap<>(); + + if (nums.length == 1) + return nums[0]; + + for (int num : nums) { + if (counter.containsKey(num)) { + if (counter.get(num) == nums.length / 2) + return num; + else + counter.put(num, counter.get(num) + 1); + } else + counter.put(num, 1); + } + + return -1; + } + + // boyer moore voting algorithm + // 100.00% 1ms 50.94% 41.5 MB + public int majorityElement(int[] nums) { + int count = 0; + int major = nums[0]; + + for (int num : nums) { + if (num == major) + count++; + else + count--; + if (count == -1) { + major = nums[0]; + count = 0; + } + } + return major; + } + + public static void main(String[] args) { + int[] array = {1, 2, 1}; + MajorityElement m = new MajorityElement(); + System.out.println(m.majorityElement(array)); + } + +} diff --git a/Week_04/id_26/Leetcode_241_26.java b/Week_04/id_26/Leetcode_241_26.java new file mode 100644 index 00000000..adb7af5f --- /dev/null +++ b/Week_04/id_26/Leetcode_241_26.java @@ -0,0 +1,106 @@ +package divideandconquer; +// Source : https://leetcode.com/problems/different-ways-to-add-parentheses/ +// Id : 241 +// Author : Fanlu Hai +// Date : 2018-05-24 +// Other : +// Tips : "improvements" can make program run slower + +import java.util.*; + +public class DifferentWaysToAddParentheses { + + //32.84% 3 ms 34.61% 39.6 MB + public List diffWaysToComputeSlow(String input) { + List result = new LinkedList<>(); + + for (int i = 0; i < input.length(); i++) { + if (input.charAt(i) == '+' || input.charAt(i) == '-' || input.charAt(i) == '*') { + String part1 = input.substring(0, i); + String part2 = input.substring(i + 1); + + List resultPart1 = new LinkedList<>(); + List resultPart2 = new LinkedList<>(); + resultPart1 = diffWaysToComputeSlow(part1); + resultPart2 = diffWaysToComputeSlow(part2); + + // when either on is empty, nothing will be added to result + for (int res1 : resultPart1) { + for (int re2 : resultPart2) { + switch (input.charAt(i)) { + case '+': + result.add(res1 + re2); + break; + case '-': + result.add(res1 - re2); + break; + case '*': + result.add(res1 * re2); + break; + } + } + } + } + } + // if nothing is added to result list, it means the string is a number + if (result.isEmpty()) + result.add(Integer.valueOf(input)); + return result; + } + + // use map to store intermediate results to speed up recursion + Map> resultCache = new HashMap<>(); + + + //1 ms 100% 34.2 MB 100% + public List diffWaysToCompute(String input) { + + if (resultCache.containsKey(input)) + return resultCache.get(input); + + List result = new LinkedList<>(); + + for (int i = 0; i < input.length(); i++) { + if (input.charAt(i) == '+' || input.charAt(i) == '-' || input.charAt(i) == '*') { + String part1 = input.substring(0, i); + String part2 = input.substring(i + 1); + + List resultPart1 = new LinkedList<>(); + List resultPart2 = new LinkedList<>(); + resultPart1 = diffWaysToCompute(part1); + resultPart2 = diffWaysToCompute(part2); + + // when either on is empty, nothing will be added to result + for (int res1 : resultPart1) { + for (int re2 : resultPart2) { + //using swith here is not very efficient + // 78.94% 2 ms 100.00% 34.2 MB + // switch (input.charAt(i)) { +// case '+': +// result.add(res1 + re2); +// break; +// case '-': +// result.add(res1 - re2); +// break; +// case '*': +// result.add(res1 * re2); +// break; +// } + if (input.charAt(i) == '+') + result.add(res1 + re2); + else if (input.charAt(i) == '-') + result.add(res1 - re2); + else + result.add(res1 * re2); + + } + } + } + } + // if nothing is added to result list, it means the string is a number + if (result.isEmpty()) + result.add(Integer.valueOf(input)); + resultCache.put(input, result); + return result; + } +}