# 212 太难了抄的官方
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
WORD_KEY = '$'
trie = {}
for word in words:
node = trie
for letter in word:
# retrieve the next node; If not found, create a empty node.
node = node.setdefault(letter, {})
# mark the existence of a word in trie node
node[WORD_KEY] = word
rowNum = len(board)
colNum = len(board[0])
matchedWords = []
def backtracking(row, col, parent):
letter = board[row][col]
currNode = parent[letter]
# check if we find a match of word
word_match = currNode.pop(WORD_KEY, False)
if word_match:
# also we removed the matched word to avoid duplicates,
# as well as avoiding using set() for results.
matchedWords.append(word_match)
# Before the EXPLORATION, mark the cell as visited
board[row][col] = '#'
# Explore the neighbors in 4 directions, i.e. up, right, down, left
for (rowOffset, colOffset) in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
newRow, newCol = row + rowOffset, col + colOffset
if newRow < 0 or newRow >= rowNum or newCol < 0 or newCol >= colNum:
continue
if not board[newRow][newCol] in currNode:
continue
backtracking(newRow, newCol, currNode)
# End of EXPLORATION, we restore the cell
board[row][col] = letter
# Optimization: incrementally remove the matched leaf node in Trie.
if not currNode:
parent.pop(letter)
for row in range(rowNum):
for col in range(colNum):
# starting from each of the cells
if board[row][col] in trie:
backtracking(row, col, trie)
return matchedWords
# 213
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
if len(nums) == 1:
return nums[0]
def helper(nums):
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp = [nums[0] , max(nums[0] , nums[1])]
for i in range(2 , len(nums)):
dp.append(max((dp[0] + nums[i]) , dp[1]))
dp.pop(0)
return dp[-1]
return max(helper(nums[1:]) , helper(nums[:-1]))
# 214
class Solution:
def shortestPalindrome(self, s: str) -> str:
r = s[::-1]
for i in range(len(s) + 1):
if s.startswith(r[i:]):
return r[:i] + s
# 215
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums.sort()
return nums[-k]
# 216
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
res = []
def helper(k , n , start , tmp):
if k == 0 and n == 0 and tmp not in res:
res.append(tmp)
return
for i in range(start , 10):
helper(k - 1 , n - i , i + 1 , tmp + [i])
helper(k , n , 1 , [])
return res
# 217
class Solution:
def containsDuplicate(self, nums):
n1 = len(nums)
n2 = len(set(nums))
if n1 == n2:
return False
return True
# 218
class Solution:
def getSkyline(self, buildings: List[List[int]]) -> List[List[int]]:
if not buildings: return []
if len(buildings) == 1:
return [[buildings[0][0], buildings[0][2]], [buildings[0][1], 0]]
mid = len(buildings) // 2
left = self.getSkyline(buildings[:mid])
right = self.getSkyline(buildings[mid:])
return self.merge(left, right)
def merge(self, left, right):
lh = rh = 0
l = r = 0
res = []
while l < len(left) and r < len(right):
if left[l][0] < right[r][0]:
cp = [left[l][0], max(left[l][1], rh)]
lh = left[l][1]
l += 1
elif left[l][0] > right[r][0]:
cp = [right[r][0], max(right[r][1], lh)]
rh = right[r][1]
r += 1
else:
cp = [left[l][0], max(left[l][1], right[r][1])]
lh = left[l][1]
rh = right[r][1]
l += 1
r += 1
if len(res) == 0 or res[-1][1] != cp[1]:
res.append(cp)
res.extend(left[l:] or right[r:])
return res
# 219
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
if len(nums) == len(set(nums)):
return False
dict1 = {}
for i in range(len(nums)):
if nums[i] not in dict1:
dict1[nums[i]] = i
else:
if i - dict1[nums[i]] <= k:
return True
dict1[nums[i]] = i
return False
# 220 (线性 可能会超时)
class Solution:
def containsNearbyAlmostDuplicate(self, A: List[int], k: int, t: int) -> bool:
if t < 0: return False
if not t:
seen = {}
for i, a in enumerate(A):
if a in seen and i-seen[a] <= k:
return True
seen[a] = i
return False
n = len(A)
for i in range(n):
for j in range(i+1, min(i+k+1, n)):
if abs(A[i] - A[j]) <= t:
return True
return False
(桶排序 o(n)能通过)
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
if t < 0 or k < 0:
return False
all_buckets = {}
bucket_size = t + 1 # 桶的大小设成t+1更加方便
for i in range(len(nums)):
bucket_num = nums[i] // bucket_size # 放入哪个桶
if bucket_num in all_buckets: # 桶中已经有元素了
return True
all_buckets[bucket_num] = nums[i] # 把nums[i]放入桶中
if (bucket_num - 1) in all_buckets and abs(all_buckets[bucket_num - 1] - nums[i]) <= t: # 检查前一个桶
return True
if (bucket_num + 1) in all_buckets and abs(all_buckets[bucket_num + 1] - nums[i]) <= t: # 检查后一个桶
return True
# 如果不构成返回条件,那么当i >= k 的时候就要删除旧桶了,以维持桶中的元素索引跟下一个i+1索引只差不超过k
if i >= k:
all_buckets.pop(nums[i-k]//bucket_size)
return False