目錄
1-Minimum Time Visiting All Points-easy。array
2-Count Servers that Communicate-medium。array
3-Search Suggestions System-medium。trie
4-Number of Ways to Stay in the Same Place After Some Steps-hard。DP
1-Minimum Time Visiting All Points-easy。array
On a plane there are n
points with integer coordinates points[i] = [xi, yi]
. Your task is to find the minimum time in seconds to visit all points.
You can move according to the next rules:
- In one second always you can either move vertically, horizontally by one unit or diagonally (it means to move one unit vertically and one unit horizontally in one second).
- You have to visit the points in the same order as they appear in the array.
Input: points = [[1,1],[3,4],[-1,0]] Output: 7 Explanation: One optimal path is [1,1] -> [2,2] -> [3,3] -> [3,4] -> [2,3] -> [1,2] -> [0,1] -> [-1,0] Time from [1,1] to [3,4] = 3 seconds Time from [3,4] to [-1,0] = 4 seconds Total time = 7 seconds
通過測試用例即可知計算相對最短路徑即可,等於兩者之間最大座標差
class Solution:
def minTimeToVisitAllPoints(self, points: List[List[int]]) -> int:
if not points:
return 0
res = 0
for i in range(1, len(points)):
cur = max(abs(points[i][0] - points[i-1][0]), abs(points[i][1] - points[i-1][1]))
res += cur
return res
2-Count Servers that Communicate-medium。array
You are given a map of a server center, represented as a m * n
integer matrix grid
, where 1 means that on that cell there is a server and 0 means that it is no server. Two servers are said to communicate if they are on the same row or on the same column. Return the number of servers that communicate with any other server.
Input: grid = [[1,1,0,0],[0,0,1,0],[0,0,1,0],[0,0,0,1]] Output: 4 Explanation: The two servers in the first row can communicate with each other. The two servers in the third column can communicate with each other. The server at right bottom corner can't communicate with any other server.
反向思考,先計算總共的server數量,再遍歷一遍把無com的結果去掉,剩下就是有com的結果
from collections import deque
class Solution:
def countServers(self, grid: List[List[int]]) -> int:
if not grid:
return 0
m = len(grid)
n = len(grid[0])
res = 0
row = [0]*m
col = [0]*n
for i in range(m):
for j in range(n):
if grid[i][j]:
res += 1
row[i] += 1
col[j] += 1
for i in range(m):
for j in range(n):
if grid[i][j] and row[i] <= 1 and col[j] <= 1:
res -= 1
return res
3-Search Suggestions System-medium。trie
Given an array of strings products
and a string searchWord
. We want to design a system that suggests at most three product names from products
after each character of searchWord
is typed. Suggested products should have common prefix with the searchWord. If there are more than three products with a common prefix return the three lexicographically minimums products.
Return list of lists of the suggested products
after each character of searchWord
is typed.
Input: products = ["bags","baggage","banner","box","cloths"], searchWord = "bags" Output: [["baggage","bags","banner"],["baggage","bags","banner"],["baggage","bags"],["bags"]]
這道題在排名靠前的解法裏沒找到Trie的解法,只有暴力匹配加一點剪枝的trick
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
products.sort()
ans = []
for i in range(len(searchWord)):
temp = []
j = 0
while j < len(products):
if searchWord[:i+1] == products[j][:i+1]:
if len(temp) < 3:
temp.append(products[j])
j += 1
else:
products.pop(j) # 剪枝,把後續query不可能索引的結果先pop掉
ans.append(temp)
return ans
# 自己的做法,我覺得更reasonable,但有bug,27/41
class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]:
if not searchWord:
return []
trie = Trie()
for pro in products:
trie.add(pro)
res = []
for i in range(1, len(searchWord)+1):
cur = searchWord[:i]
ans = trie.search(cur)
res.append(ans)
return res
class Trie:
def __init__(self):
self.root = {}
self.end = True
def add(self, w):
add = self.root
for c in w:
add[c] = add.get(c, {})
add = add[c]
add[self.end] = True
def search(self, w):
search = self.root
for c in w:
if c not in search:
return []
search = search[c]
res = []
self.dfs(search, res, w)
return res
def dfs(self, dic, res, path):
if not dic or self.end in dic:
res.append(path)
if len(res) >= 3:
return
for c in 'abcdefghijklmnopqrstuvwxyz':
if c not in dic:
continue
if len(res) >= 3:
break
self.dfs(dic[c], res, path + c)
return res
4-Number of Ways to Stay in the Same Place After Some Steps-hard。DP
You have a pointer at index 0
in an array of size arrLen
. At each step, you can move 1 position to the left, 1 position to the right in the array or stay in the same place (The pointer should not be placed outside the array at any time).
Given two integers steps
and arrLen
, return the number of ways such that your pointer still at index 0
after exactly steps
steps.
Since the answer may be too large, return it modulo 10^9 + 7
.
Constraints:
1 <= steps <= 500
1 <= arrLen <= 10^6
Input: steps = 2, arrLen = 4 Output: 2 Explanation: There are 2 differents ways to stay at index 0 after 2 steps Right, Left Stay, Stay
這道題keys是2個
- 涉及到steps和arrLen,所以是個二元DP問題,想清楚dp[i][j]的含義,這裏是耗步數i步停留在下標爲j的可能性數量
- 轉換方程。dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + dp[i-1][j+1],表示再i-1的基礎上,再走一步到j位置,對應stay + right + left。這裏一開始錯誤理解了題意,以爲可以向左向右跳任意步長,實際只能跳1步
- 邊界條件,初始化爲0,默認dp[i][j] = 1
- critical trick,這裏arrLen如果比steps更長,更長的部分是沒有意義的,因爲最遠也跳不到超過steps的位置,所以這裏可以剪枝,把更長的部分減掉(否則後續會TLE,看constraints就知道)
class Solution:
def numWays(self, steps: int, arrLen: int) -> int:
if arrLen > steps: # important trick
arrLen = steps
MOD = 10**9 + 7
dp = [[0 for _ in range(arrLen+1)] for _ in range(steps+1)]
dp[0][0] = 1
for i in range(1, steps+1):
for j in range(arrLen+1):
dp[i][j] += dp[i-1][j]
for k in [-1, 1]:
if j+k >= 0 and j+k < arrLen:
dp[i][j] += dp[i-1][j+k]
dp[i][j] %= MOD
return dp[steps][0]