up | created | modified | cssclasses | |||
---|---|---|---|---|---|---|
|
2024-06-25 |
2024-07-25 |
|
TODO: Currently DV only support loading from csv
- If I want the [[Leetcode map.canvas|Leetcode dashboard]] to update by category (i.e. in a DP box of dashboard, list all DP problems I've done)
- need to use separate file (csv) as broker, basically a script that move the table here to csv in a separate file :/
Problem | Solution | Category | Leetcode Difficulty | Solved myself? | Solved optimal? | Note |
---|---|---|---|---|---|---|
LC 347. Top K Frequent | [[#LC 347. Top K Frequent|link]] | Hard | Y | N | ||
LC 271. Encode Decode String | [[#LC 271. Encode Decode Strings|link]] | Medium | Y | Y | ||
LC 212. Word Search II | [[#LC 212. Word Search II|link]] | Hard | N | - | ||
LC 70. Climbing Stairs | [[#LC 70. Climbing Stairs|link]] | [[Dynamic Programming]] | Easy | Y (well with hint) | Y | |
LC 23. Merge K Sorted List | [[#LC 23. Merge K Sorted List|link]] | Hard | Y | Y (kinda) | ||
LC 49. Group Anagrams | [[#LC 49. Group Anagram|link]] | Medium | Y | N | ||
LC 39. Combination Sum | [[#LC 39. Combination Sum|link]] | [[Backtracking]] | Medium | Y | ||
LC 79. Word Search | [[#LC 79. Word Search|link]] | Medium | Y | Y | ||
LC 200. Number of Island | [[#LC 200. Number of Island|link]] | [[Graph data structure|Graph]] | ||||
LC 2685. Count the Number of Complete Components | [[#LC 2685. Count the Number of Complete Components|link]] | [[Graph data structure|Graph]] | ||||
LC 133. Clone Graph | link | [[Graph data structure|Graph]] | ||||
LC 417. Pacific Atlantic Water Flow | link | [[Graph data structure|Graph]] | ||||
fewoij | ||||||
f | ||||||
dqwoijoifew | ||||||
foewijiodqw | ||||||
dqwoiio |
O(mn)
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m = len(board)
n = len(board[0]) if m >= 1 else 0
def dfs(i, j, z) -> bool:
if i >= m or i < 0 or j >= n or j < 0:
return False
if word[z] == board[i][j]:
z += 1
if z == len(word):
return True
else:
return False
# search in four directions
currChar = board[i][j]
board[i][j] = '*'
r = dfs(i + 1, j, z)
r = r or dfs(i - 1, j, z)
r = r or dfs(i + 1, j, z)
r = r or dfs(i, j - 1, z)
r = r or dfs(i, j + 1, z)
board[i][j] = currChar
return r
for i in range(m):
for j in range(n):
if dfs(i, j, 0):
return True
return False
class Solution:
def combinationSum(self, nums: List[int], target: int) -> List[List[int]]:
result = []
# set of sets
lookup = set()
def getCombination(sums, currSum):
if currSum < 0:
return
if currSum == 0:
s = str(sorted(sums))
if s not in lookup:
lookup.add(s)
result.append(list(sums))
return
for n in nums:
if n <= currSum:
sums.append(n)
getCombination(sums, currSum - n)
sums.pop()
getCombination([], target)
return result
K unique element will repeat K! times
My solution
O(NKlog(K)), k = string length, N = n strings
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
l = {}
for s in strs:
h = hash(''.join(sorted(s)))
if h in l:
l[h].append(s)
else:
l[h] = [s]
res = []
for _, v in l.items():
res.append(v)
return res
Optimal: O(N)
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
ans = defaultdict(list)
for s in strs:
count = [0] * 26
for c in s:
count[ord(c) - ord("a")] += 1
ans[tuple(count)].append(s)
return ans.values()
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
import heapq
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
h = []
heapq.heapify(h)
head = None
currNode = None
for n in lists:
if n:
tup = (n.val, id(n), n)
print(tup)
heapq.heappush(h, tup)
while len(h) > 0:
_, _, n = heapq.heappop(h)
if n.next:
heapq.heappush(h, (n.next.val, id(n.next), n.next))
if not head:
head = n
currNode = head
else:
currNode.next = n
currNode = n
if currNode:
currNode.next = None
return head
class Solution {
private HashMap<Integer, Integer> memo = new HashMap<Integer, Integer>();
public int climbStairs(int n) {
if (memo.getOrDefault(n, -1) != -1) {
return memo.get(n);
}
if (n == 0) {
return 1;
}
if (n < 0) {
return 0;
}
int solution = climbStairs(n - 1) + climbStairs(n - 2);
memo.put(n, solution);
return solution;
}
}
class TrieNode:
def __init__(self):
self.children: Dict[str, TrieNode] = {}
self.word: Optional[str] = None
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
m = len(board)
n = len(board[0])
ans = []
root = TrieNode()
def insert(word: str) -> None:
node = root
for c in word:
## commented code is WRONG, because if node children already exists, then this still go ahead
## and change the node reference to that newNode created
## effectively this doesn't build the Trie correctly
# newNode = TrieNode()
# node.children.setdefault(c, newNode)
# node = newNode
node = node.children.setdefault(c, TrieNode())
node.word = word
for w in words:
insert(w)
def dfs(i: int, j: int, node: TrieNode) -> None:
# check out of bound
if i < 0 or i == len(board) or j < 0 or j == len(board[0]):
return
if board[i][j] == "*":
return
c = board[i][j]
# add current c to node
# check if node is complete
if c in node.children:
n = node.children[c]
if n.word:
ans.append(n.word)
# "pop" from words to find
n.word = None
# recurse
board[i][j] = "*"
dfs(i-1, j, n)
dfs(i+1, j, n)
dfs(i, j-1, n)
dfs(i, j+1, n)
board[i][j] = c
for i in range(m):
for j in range(n):
dfs(i, j, root)
return ans
# My idea without using Trie and just dfs
class Solution:
# search(prefix, suffix, vistedCoordinates, memoize) -> found
# found when suffix = 0
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
# 1. arrange words to prefix (w[0]) and suffix (w[1:])
# 2. for each word prefix, if character at board coordinate = prefix
# add call stack for search
# 3. call search, if true add to result
# search would look adjacent to board, if it's the first character of suffix, recursion with prefix changed
My Solutions:
encode the separator information only in the string
import re
class solution:
def encode(self, strs: list[str]) -> str:
if len(strs) == 0:
return '[]'
res = []
for s in strs:
res.append(s.replace('-', '\-'))
return '-'.join(res)
def decode(self, s: str) -> list[str]:
if s == '[]':
return []
l = re.split(r'(?<!\\)-', s)
res = []
for w in l:
res.append(re.sub(r'\\-', '-', w))
return res
His Solution
More elegant than mine, encode separate AND the length information in the string
class Solution:
def encode(self, strs: List[str]) -> str:
res = ""
for s in strs:
res += str(len(s)) + "#" + s
return res
def decode(self, s: str) -> List[str]:
res = []
i = 0
while i < len(s):
j = i
while s[j] != '#':
j += 1
length = int(s[i:j])
i = j + 1
j = i + length
res.append(s[i:j])
i = j
return res
My solution
Worst case: O(nlogn)
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
numFreq = {}
for num in nums:
freq = numFreq.setdefault(num, 0)
numFreq[num] = freq + 1
res = [k for k,v in sorted(numFreq.items(), key=lambda item: item[1])]
return res[len(res) - k:]
His solution
O(n), using array position itself as holder of frequency
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freqNum = [[] for i in range(len(nums) + 1)]
numFreq = {}
for num in nums:
numFreq[num] = numFreq.get(num, 0) + 1
for num, count in numFreq.items():
freqNum[count].append(num)
res = []
for i in range(len(freqNum) - 1, 0, -1):
for n in freqNum[i]:
res.append(n)
if len(res) == k:
return res