[LeetCode] Interview Questions
- 49 - Group Anagrams @ leetcode solution
- 102 - Binary Tree Level Order Traversal - BFS @neetcode
- 150 - Evaluate Reverse Polish Notation:explanation
Array & Hashing
Range Sum Query - Immutable - LeetCode 303
解題邏輯
- 利用 Prefix Sum 的方法,只需要先算出這個 Array 從 0 到 end 累加到數值,假設取做 sumArray
- 要取得 L 到 R 的加總,只需要
sumArray[R] - sumArray[L - 1]
- 例外,如果
L = 0
則直接拿sumArray[R]
- 例外,如果
Binary Search
Koko Eating Bananas - Leetcode 875
題目描述
- 給定一組 array of numbers(
piles
) - 需要在
h
次內消耗完所有數字 - 每次能消耗
k
個,但最多就是消耗完一個 pile,且消耗的速度(k)要約小越好
需要求 k
的值。
解題邏輯
- 題目有一個前提是
piles.length <= h
,否則一定消耗不完 - 由於題目希望
k
越小越好,所以k
最大就是等於 piles 裡面的最大值,超過這個數字也沒意義,也就是k <= Max(piles)
- 這時候就可以列出所有可能 k,例如,
[3, 6, 7, 11]
則可以列出[1, ... 11]
- 最後,使用 Binary Search 找出符合的答 案
參考程式碼
/**
* @param {number[]} piles
* @param {number} h
* @return {number}
*/
var minEatingSpeed = function (piles, h) {
let l = 1;
let r = piles.reduce((acc, pile) => acc + pile);
while (l <= r) {
const m = Math.floor((l + r) / 2);
const hours = piles.reduce((acc, pile) => acc + Math.ceil(pile / m), 0);
// 1. 如果用的時間比規定的多,需要把一 次消耗的量(k)加大
if (hours > h) {
l = m + 1;
} else {
// hours <= h
r = m - 1;
}
}
// 2. 之所以可以直接回傳 l 是因為我們要的是最小值
return l;
};
Trees
Binary Tree Level Order Traversal - LeetCode 102
題目描述
透過 BFT(Breadth First Traversal)把所有元素以 two dimensional array 的方式呈現出來
- 需要以左到右的方式排列
解題邏輯
- 透過迴圈
- 把每一層的 node 都放到 queue 中
- 每次都會把 queue 的 node 清空,保存到該層所建立的 array 中
- 把下一層的 node 都放到 queue 中
- 重複這個邏輯...
範例程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function (root) {
const result = [];
const queue = [root];
if (!root) {
return result;
}
while (queue.length) {
const level = [];
// 因為 queue 會被改變,所以先把這個迴圈開始前的 length 記下來
// 如此才知道怎麼每次把 queue 都清空
const queueLength = queue.length;
// 每次都把 queue 清空
for (let i = 0; i < queueLength; i++) {
const currentNode = queue.shift();
level.push(currentNode.val);
if (currentNode.left) {
queue.push(currentNode.left);
}
if (currentNode.right) {
queue.push(currentNode.right);
}
}
result.push(level);
}
return result;
};
Invert Binary Tree - LeetCode 226
題目描述
把所有 node 底下的 left 和 right 對調
解題邏輯
這題要想到用 recursive,把每一個 node 的 left 和 right 都進行交換
參考程式碼
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function (root) {
if (!root) return null;
const tempRoot = { ...root };
root.left = invertTree(tempRoot.right);
root.right = invertTree(tempRoot.left);
return root;
};
Count Good Nodes in Binary Tree - LeetCode 1448
題目描述
- Good Node 指的是 Parent Node 中沒有比它值更大的
- Root Node 是 Good Node
- 要計算整個 Tree 中,Parent Nodes 的數量
解題邏輯
使用 DFT(Depth First Traversal)或 BFT(Breadth First Traversal)都可以。
如果是使用 DFT 的話,可以使用 Pre-Order 的方式進行遍歷,一樣將問題縮限在一個小區域在用 recursive 重複此邏輯。
範例程式碼
DFS
var goodNodes = function (root) {
function dfs(node, maxValue) {
let result = 0;
let nextMaxValue = maxValue;
// node 不存在就不用再往下找
if (!node) return result;
if (node.val >= maxValue) {
// 修改 maxValue
nextMaxValue = node.val;
// GoodNode + 1
result = 1;
}
result += dfs(node.left, nextMaxValue);
result += dfs(node.right, nextMaxValue);
return result;
}
return dfs(root, root.val);
};
BFS
var goodNodes = function (root) {
let result = 0;
if (!root) return result;
// type Queue = [TreeNode, MaxValue][]
const queue = [[root, root.val]];
while (queue.length) {
const queueLength = queue.length;
for (let i = 0; i < queueLength; i++) {
let [currentNode, maxValue] = queue.shift();
if (currentNode.val >= maxValue) {
maxValue = currentNode.val;
result++;
}
if (currentNode.left) {
queue.push([currentNode.left, maxValue]);
}
if (currentNode.right) {
queue.push([currentNode.right, maxValue]);
}
}
}
return result;
};
Sliding Window
Longest Substring Without Repeating Characters - LeetCode 3
題目描述
回傳字串 s
中不重複 substring 的長度
解題邏輯
使用 Sliding Window 的作法:
- 先定義
l = 0
r
則透過迴圈依序增加
使用 Set 來判斷單字是不是已經保存過:
- 把單字依序加入 Set 中,如果 Set 中已經重複,就要刪到該重複的字為止,例如
abcbb
,當[abc]
在遇到下一個b
時,需要把原本 Set 裡的ab
都刪掉
參考答案
var lengthOfLongestSubstring = function (s) {
let result = 0;
// 使用 Set 來判斷單字是不是出現過
const charSet = new Set();
// 定義 sliding window 的 l 和 r
let l = 0;
for (let r = 0; r < s.length; r++) {
// 如果 charSet 中已經存在這個字,要把所有這個字以左的都一併從 Set 中刪除
while (charSet.has(s[r])) {
charSet.delete(s[l]);
l++;
}
charSet.add(s[r]);
// 也可以寫 result = Math.max(result, charSet.size);
result = Math.max(result, r - l + 1);
}
return result;
};
Dynamic Programming
Longest Palindromic Substring - LeetCode 5
題目描述
- 從一個字串(
s
)中找出最長的回文字串,有兩種可能- 答案是奇數次(odd),例如,
aba
、dcacd
- 答案是偶數次(even),例如,
baab
、caab
- 答案是奇數次(odd),例如,
解題邏輯
把某一個字當成中點(n
),往左右兩邊找(l
, r
)
- 只要
l >= 0
且r <= s.length
,且s[l] === s[r]
就可以一直找
範例程式碼
while
裡面的內容基本上是重複的,可以考慮抽成 function
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
let result = '';
let resultLength = 0;
[...s].forEach((_, idx) => {
// handle odd length cases
let l = idx;
let r = idx;
while (l >= 0 && r <= s.length && s[l] === s[r]) {
const length = r - l + 1;
if (length > resultLength) {
result = s.slice(l, r + 1);
resultLength = length;
}
l--;
r++;
}
// handle even length cases
l = idx;
r = idx + 1;
while (l >= 0 && r <= s.length && s[l] === s[r]) {
const length = r - l + 1;
if (length > resultLength) {
result = s.slice(l, r + 1);
resultLength = length;
}
l--;
r++;
}
});
return result;
};
Palindromic Substrings - LeetCode 647
解題邏輯
這題的思路和 Longest Palindromic Substring(LeetCode 5)是一樣的。
參考答案
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function (s) {
function countPali(l, r) {
let count = 0;
while (l >= 0 && r <= s.length && s[l] === s[r]) {
count++;
l--;
r++;
}
return count;
}
let result = 0;
[...s].forEach((_, idx) => {
// handle old cases
result += countPali(idx, idx);
// handle even cases
result += countPali(idx, idx + 1);
});
return result;
};
Decode Ways - LeetCode 91
題目描述
- 把每一個大寫英文字母編碼,"A" 是 1、"B" 是 2、...、"Z" 是 26
- 題目會給一個字串作為 input,回傳所有「合法」結果的次數。例如,當 input 是
12
,可能的結果為(1, 2)
和(12)
,所以答案是 2;當 input 是06
,因為它無法組成任何合法的數字,所以答案是 0。
解題邏輯
合法的 digit
- 最多是兩位數,所以它會是一個 binary 的 decision tree
- 從最左邊開始,每次可以決定要拿一位數或兩位數,例如,如果是
121
,則開始有1
或12
兩種可能
數字會是 1 ~ 26
- 如果第一個數字是
0
,一定是不合法的 - 如果第一個數字是
1
,後面可以是0 ~ 9
- 如果第一個數字是
2
,後面可以是0 ~ 6
- 如果第一個數字
> 2
,後面不能有任何數字