|
| 1 | +## 每日一题 - Longest Common Prefix |
| 2 | + |
| 3 | +### 信息卡片 |
| 4 | + |
| 5 | +- 时间:2019-06-03 |
| 6 | +- 题目链接:https://leetcode.com/problems/longest-common-prefix/ |
| 7 | +- tag:`trie` `binary search` |
| 8 | + |
| 9 | +### 题目描述 |
| 10 | + |
| 11 | +``` |
| 12 | +Write a function to find the longest common prefix string amongst an array of strings. |
| 13 | +
|
| 14 | +If there is no common prefix, return an empty string "". |
| 15 | +
|
| 16 | +Example 1: |
| 17 | +Input: ["flower","flow","flight"] |
| 18 | +Output: "fl" |
| 19 | +
|
| 20 | +Example 2: |
| 21 | +Input: ["dog","racecar","car"] |
| 22 | +Output: "" |
| 23 | +Explanation: There is no common prefix among the input strings. |
| 24 | +
|
| 25 | +Note: |
| 26 | +All given inputs are in lowercase letters a-z. |
| 27 | +``` |
| 28 | + |
| 29 | +### 参考答案 |
| 30 | + |
| 31 | +#### 二分法 |
| 32 | +- 找到字符串数组中长度最短字符串 |
| 33 | +- longest common prefix 长度范围 0 ~ minLength |
| 34 | +- 运用`binary search` |
| 35 | + |
| 36 | +参考代码 |
| 37 | +```javascript |
| 38 | +/* |
| 39 | + * @lc app=leetcode id=14 lang=javascript |
| 40 | + * |
| 41 | + * [14] Longest Common Prefix |
| 42 | + */ |
| 43 | + |
| 44 | +function isCommonPrefix(strs, middle) { |
| 45 | + const prefix = strs[0].substring(0, middle); |
| 46 | + for (let i = 1; i < strs.length; i++) { |
| 47 | + if (!strs[i].startsWith(prefix)) return false; |
| 48 | + } |
| 49 | + |
| 50 | + return true; |
| 51 | +} |
| 52 | +/** |
| 53 | + * @param {string[]} strs |
| 54 | + * @return {string} |
| 55 | + */ |
| 56 | +var longestCommonPrefix = function(strs) { |
| 57 | + // trie 解法 |
| 58 | + // 时间复杂度O(m) 空间复杂度O(m * n) |
| 59 | + |
| 60 | + // tag: 二分法 |
| 61 | + // 时间复杂度 O(n*logm) 空间复杂度O(1) |
| 62 | + if (strs.length === 0) return ""; |
| 63 | + if (strs.length === 1) return strs[0]; |
| 64 | + |
| 65 | + let minLen = Number.MAX_VALUE; |
| 66 | + |
| 67 | + for (let i = 0; i < strs.length; i++) { |
| 68 | + minLen = Math.min(minLen, strs[i].length); |
| 69 | + } |
| 70 | + |
| 71 | + let low = 0; |
| 72 | + let high = minLen; |
| 73 | + |
| 74 | + while (low <= high) { |
| 75 | + const middle = (low + high) >> 1; |
| 76 | + if (isCommonPrefix(strs, middle)) low = middle + 1; |
| 77 | + else high = middle - 1; |
| 78 | + } |
| 79 | + |
| 80 | + return strs[0].substring(0, (low + high) >> 1); |
| 81 | +}; |
| 82 | +``` |
| 83 | +#### trie树 |
| 84 | +以LeetCode另一道题[Implement Trie](https://leetcode.com/problems/implement-trie-prefix-tree/description/)的解法作为本题的参考思路, 具体代码可以自行补充完善 |
| 85 | + |
| 86 | +- 建立 Trie |
| 87 | +- 遍历到有一个children有超过一个子元素为止 |
| 88 | + |
| 89 | + |
| 90 | +Trie实现参考代码 |
| 91 | +```javascript |
| 92 | +/* |
| 93 | + * @lc app=leetcode id=208 lang=javascript |
| 94 | + * |
| 95 | + * [208] Implement Trie (Prefix Tree) |
| 96 | + * |
| 97 | + * https://leetcode.com/problems/implement-trie-prefix-tree/description/ |
| 98 | + * |
| 99 | + * algorithms |
| 100 | + * Medium (36.93%) |
| 101 | + * Total Accepted: 172K |
| 102 | + * Total Submissions: 455.5K |
| 103 | + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' |
| 104 | + * |
| 105 | + * Implement a trie with insert, search, and startsWith methods. |
| 106 | + * |
| 107 | + * Example: |
| 108 | + * |
| 109 | + * |
| 110 | + * Trie trie = new Trie(); |
| 111 | + * |
| 112 | + * trie.insert("apple"); |
| 113 | + * trie.search("apple"); // returns true |
| 114 | + * trie.search("app"); // returns false |
| 115 | + * trie.startsWith("app"); // returns true |
| 116 | + * trie.insert("app"); |
| 117 | + * trie.search("app"); // returns true |
| 118 | + * |
| 119 | + * |
| 120 | + * Note: |
| 121 | + * |
| 122 | + * |
| 123 | + * You may assume that all inputs are consist of lowercase letters a-z. |
| 124 | + * All inputs are guaranteed to be non-empty strings. |
| 125 | + * |
| 126 | + * |
| 127 | + */ |
| 128 | +function TrieNode(val) { |
| 129 | + this.val = val; |
| 130 | + this.children = []; |
| 131 | + this.isWord = false; |
| 132 | +} |
| 133 | + |
| 134 | +function computeIndex(c) { |
| 135 | + return c.charCodeAt(0) - "a".charCodeAt(0); |
| 136 | +} |
| 137 | +/** |
| 138 | + * Initialize your data structure here. |
| 139 | + */ |
| 140 | +var Trie = function() { |
| 141 | + this.root = new TrieNode(null); |
| 142 | +}; |
| 143 | + |
| 144 | +/** |
| 145 | + * Inserts a word into the trie. |
| 146 | + * @param {string} word |
| 147 | + * @return {void} |
| 148 | + */ |
| 149 | +Trie.prototype.insert = function(word) { |
| 150 | + let ws = this.root; |
| 151 | + for (let i = 0; i < word.length; i++) { |
| 152 | + const c = word[i]; |
| 153 | + const current = computeIndex(c); |
| 154 | + if (!ws.children[current]) { |
| 155 | + ws.children[current] = new TrieNode(c); |
| 156 | + } |
| 157 | + ws = ws.children[current]; |
| 158 | + } |
| 159 | + ws.isWord = true; |
| 160 | +}; |
| 161 | + |
| 162 | +/** |
| 163 | + * Returns if the word is in the trie. |
| 164 | + * @param {string} word |
| 165 | + * @return {boolean} |
| 166 | + */ |
| 167 | +Trie.prototype.search = function(word) { |
| 168 | + let ws = this.root; |
| 169 | + for (let i = 0; i < word.length; i++) { |
| 170 | + const c = word[i]; |
| 171 | + const current = computeIndex(c); |
| 172 | + if (!ws.children[current]) return false; |
| 173 | + ws = ws.children[current]; |
| 174 | + } |
| 175 | + return ws.isWord; |
| 176 | +}; |
| 177 | + |
| 178 | +/** |
| 179 | + * Returns if there is any word in the trie that starts with the given prefix. |
| 180 | + * @param {string} prefix |
| 181 | + * @return {boolean} |
| 182 | + */ |
| 183 | +Trie.prototype.startsWith = function(prefix) { |
| 184 | + let ws = this.root; |
| 185 | + for (let i = 0; i < prefix.length; i++) { |
| 186 | + const c = prefix[i]; |
| 187 | + const current = computeIndex(c); |
| 188 | + if (!ws.children[current]) return false; |
| 189 | + ws = ws.children[current]; |
| 190 | + } |
| 191 | + return true; |
| 192 | +}; |
| 193 | + |
| 194 | +/** |
| 195 | + * Your Trie object will be instantiated and called as such: |
| 196 | + * var obj = new Trie() |
| 197 | + * obj.insert(word) |
| 198 | + * var param_2 = obj.search(word) |
| 199 | + * var param_3 = obj.startsWith(prefix) |
| 200 | + */ |
| 201 | +``` |
| 202 | +#### 暴力法 |
| 203 | + |
| 204 | +比较常规的一种解法, 大部分人采用的做法, 这里就不再赘述 |
| 205 | + |
| 206 | +### 其他优秀解答 |
| 207 | +``` |
| 208 | +暂无 |
| 209 | +``` |
0 commit comments