classSolution: defmaxSubArray(self, nums: List[int]) -> int: n = len(nums) res = [Nonefor _ inrange(n)] res[0] = nums[0] for i inrange(1, n): res[i] = res[i - 1] + nums[i]
min_ = [Nonefor _ inrange(n)] min_[0] = 0 for i inrange(1, n): min_[i] = min(min_[i - 1], res[i - 1]) ans = float('-inf') for i inrange(n): ans = max(ans, res[i] - min_[i]) return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution: defmaxSubArray(self, nums: List[int]) -> int: n = len(nums) if n == 0: return0 if n == 1: return nums[0] result = [0] * n result[0] = nums[0] ans = nums[0] for i inrange(1, n): # Automaticlly drop the prefix when it become a negative number # result[i] stores the maximum sum of subarrays when they are end with i result[i] = max(result[i - 1] + nums[i], nums[i]) ans = max(ans, result[i]) return ans
classSolution: defmaxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int: n = len(customers) res = 0 for i inrange(n): ifnot grumpy[i]: res += customers[i]
ans = 0 for i inrange(minutes): if grumpy[i]: ans += customers[i]
res_m = ans for i inrange(minutes, n): if grumpy[i - minutes]: ans -= customers[i - minutes] if grumpy[i]: ans += customers[i]
find1 = find1_left or find1_right find2 = find2_left or find2_right if root.val == o1: if find2: self.ans = root returnTrue, find2 if root.val == o2: if find1: self.ans = root return find1, True if (find1_left or find2_left) and (find1_right or find2_right): self.ans = root return find1, find2 dfs(root) return self.ans.val
classSolution: deftotalNQueens(self, n: int) -> int: defbacktrack(row: int) -> int: # fill the row # two kinds of return
# when row == n, the last row (n - 1) is filled # thus it must be only 1 solution to reach here so return 1
# if row < n - 1, the solution there is may be multiple solutions # clear the count (count = 0), then find the number of solutions # and return it
# thus this function calculates the number of solutions when the first # row - 1 rows is filled, how they are filled are recorded by columns, # diagonal1 and giagonal2
# two key points: # 1. How the backtrack end: that is the condition return 1 # 2. How to transfer the task to a smaller one, that is else.
# we can crop it if and only if row == n, thus we only need # to transfer the task to a simpler one till we can crop it if row == n: return1 else: count = 0 for i inrange(n): # i is the columns if it is used continue # two position A and B, if their row -/+ i is the same number # they are in one diagonal then continue if i in columns or row - i in diagonal1 or row + i in diagonal2: continue columns.add(i) diagonal1.add(row - i) diagonal2.add(row + i) count += backtrack(row + 1) columns.remove(i) diagonal1.remove(row - i) diagonal2.remove(row + i) return count
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right classSolution: defcountNodes(self, root: TreeNode) -> int: res = [1, 0]
defwide_first_search(cur_nodes): res[0] += 1 nex_nodes = [] flag = True
for i in cur_nodes: if i.left and i.right: nex_nodes.append(i.left) nex_nodes.append(i.right) else: flag = False res[1] = len(nex_nodes) if i.left or i.right: res[1] += 1 break if flag: wide_first_search(nex_nodes)
# depth first while cur: nex = [] for i in cur: visited.add(i) for j in rooms[i]: keys.add(j) ifnot j in visited: nex.append(j) cur = nex returnlen(keys) == num_rooms
# depth first while cur: nex = [] for i in cur: visited.add(i) for j in rooms[i]: ifnot j in visited: nex.append(j) cur = nex returnlen(visited) == num_rooms
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right
defdfs(self, node): ifnot node: return0 # left sum sum_left = self.dfs(node.left) # right sum sum_right = self.dfs(node.right) # for every node the distance is the left sum - right sum self.ans += abs(sum_left - sum_right) # calculate the sum return sum_left + sum_right + node.val
If StartA can reach startB by one step, then the answer is 1
if there is a circle large than 3 nodes, and B can reach it earlier than A,
the answer is -1. Which means that if there is any node that B can reach
earlier than A.
If B can reach a node 2 or more steps earlier than A. A can only catch B in
the end. Thus choose the max step that A will take between these nodes.
classSolution: defchaseGame(self, edges: List[List[int]], startA: int, startB: int) -> int: # the number of paths and the number of nodes n=len(edges) # the node a can reach d[a] by one step d=defaultdict(list) for a,b in edges: d[a].append(b) d[b].append(a)
defcalcDist(node): que=[node] dist,step={},0 while que: tmp=[] for q in que: if q in dist: continue # node needs dist[q] step to reach q dist[q]=step for nxt in d[q]: tmp.append(nxt) que=tmp step+=1 return dist
circleNodes,depthdict=set(),{}
deffindCircle(parent,node,depth): # if already know the depth of node # return it if node in depthdict: return depthdict[node]
# 1 can reach a by depthdict[a] steps depthdict[node]=depth for nxt in d[node]: # a's parent be in d[a] # and it must be searched if nxt==parent: continue
# find the step of nxt by node mindepth=findCircle(node,nxt,depth+1) # if mindepth != depth + 1, the nxt can be reached # by another way both from one start, thus node can be # reached by another way too, there must # be a circle, and node and nxt are in the circle # regard the circle as one node and both node and nxt # have the same depth, the minstep that can reach the # circle if mindepth != depth + 1: depthdict[node]= min(mindepth, depth) circleNodes.add(node) return depthdict[node]
findCircle(-1,1,0) distA,distB=calcDist(startA),calcDist(startB) # startA reaches startB by 1 step if distA[startB]==1: return1 iflen(circleNodes)>3: for node in circleNodes: # if the circle is larger than 3 # and there are one node in the circle that B reach first # then A can never catch B if distB[node]<distA[node]: return -1 # B reach node earlyer than 2 steps before A # if only 1 step earler it should be catched before returnmax(distA[node] for node inrange(1,n+1) if distA[node]-distB[node]>1)
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right classSolution(object): defdistributeCoins(self, root): self.ans = 0
defdfs(node): ifnot node: return0 # the number of coins needed for the right node and # the left node to set them into 1 L, R = dfs(node.left), dfs(node.right)
# remove the abs(L) and abs(R) from this node to the left # node and right node then they are 1 self.ans += abs(L) + abs(R) # the number of coins needed for this node return node.val + L + R - 1
@lru_cache(None) # save the storage deffind_max(i, j): # find the next value and try the four directions # return the longest direction. max_ = 1 for dr in Solution.DIRS: try_i = i + dr[0] try_j = j + dr[1] # the direction will be discarded if do not meet the condition # and a direction meet the condition will be searched for the next # value first. if0 <= try_i and try_i < n and0<= try_j and try_j < m and \ matrix[i][j] < matrix[try_i][try_j]: max_ = max(max_, find_max(try_i, try_j) + 1) # The value is increasing, so by setting `matrix[i][j] \ # < matrix[try_i][try_j]`, a searched position will never # be searched again. return max_
n, m = len(matrix), len(matrix[0]) res = 0 for i inrange(n): for j inrange(m): res = max(res, find_max(i, j)) return res
7.8. Keyboard
A keyboard only have 26 keys, a~z. Each key can be only typed k times at
most.
How many possible content there is, when the keyboard is typed n times?
classSolution: # depth first search: from the first letter to the last letter # fill the n positions. defkeyboard(self, k: int, n: int) -> int: MOD = 1000000007
# c is the number of remain letters # n is the number of letters needed to type in # k is the max number that each letter can type @lru_cache(None) defdfs(c, n, k): if n == 0: # no letters is needed any more # only 1 way: type nothing # pick 0 letters return1 if c <= 0: # no letter remained but n is not 0 # this is a failed type scheme return0 res = 0 for i inrange(0, min(n, k) + 1): # there are math.comb(n, i) ways to put i letters # into n position. res += math.comb(n, i) * dfs(c-1, n - i, k) % MOD return res % MOD ans = dfs(26, n, k) return ans % MOD
classSolution: defkeyboard(self, k: int, n: int) -> int: MOD = 1000000007 res = [[0for _ inrange(27)] for _ inrange(n + 1)] # res[i][j] is the number of possibilities when first j letters # is used to fill i positions. # when the position is 0, no matter how many letters are used. # there is only one possibility, i.e., filling nothing. # thus, res[0][i] are all 1. res[0][0] = 1 for i inrange(27): res[0][i] = 1
# res[i][j] can be divided into several possibilities. # When 0 letter is filled for the $j^{th}$ letter, res[i][j-1] # when 1 letter is filled for the j-th letter, res[i-1][j-1] # * C_i^1 # when 2 letters are filled for the j-th letter, res[i-2][j-1] # * C_i^2 # C_i^m represent how many possibilities there are filling m of # the same letters into i positions. # m can be 0, but can not be larger than k or i. for i inrange(1, n + 1): for j inrange(1, 27): for m inrange(min(i + 1, k + 1)): res[i][j] += res[i - m][j - 1] * math.comb(i, m) res[i][j] %= MOD
classSolution: defminCut(self, s: str) -> int: n = len(s) g = [[True] * n for _ inrange(n)]
# Calculate if s[i:j + 1] is a palindrome for i inrange(n - 1, -1, -1): for j inrange(i + 1, n): # if s[i + 1 : j] is a palindrome # and s[i] == s[j] then s[i:j + 1] # is a palindrome g[i][j] = (s[i] == s[j]) and g[i + 1][j - 1]
f = [float("inf")] * n # f[i] is the min cuts for s[0: i+1] for i inrange(n): if g[0][i]: f[i] = 0 else: for j inrange(i): if g[j + 1][i]: f[i] = min(f[i], f[j] + 1) return f[n - 1]
classSolution: defminCost(self, n: int, cuts: List[int]) -> int: # the number of cuts m = len(cuts) cuts = [0] + sorted(cuts) + [n]
f = [[0] * (m + 2) for _ inrange(m + 2)] # f[i][j] means the minimal cost of [i-1, j+1] # thus f[1][m] is the answer # f[i][i] is the minimal cost of [i -1, i + 1] # which is cut[i+1] - cut[i -1] # when j > i, f[i][j] = cut[j + 1] - cut[i - 1] + min(xxxx) for i inrange(m, 0, -1): for j inrange(i, m + 1): if i == j: f[i][j] = 0 else: f[i][j] = min(f[i][k - 1] + f[k + 1][j] for k inrange(i, j + 1))
classSolution: defuniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: m = len(obstacleGrid) n = len(obstacleGrid[0]) res = [[0for _ inrange(n)] for _ inrange(m)]
for i inrange(n): if obstacleGrid[0][i] == 0: res[0][i] = 1 else: break
for i inrange(m): if obstacleGrid[i][0] == 0: res[i][0] = 1 else: break
for i inrange(1, m): for j inrange(1, n): if obstacleGrid[i][j] == 0: res[i][j] = res[i][j - 1] + res[i - 1][j] return res[-1][-1]
8.4. Find Two Non-overlapping Sub-arrays Each With Target Sum [2022-07-07]
classSolution: defminSumOfLengths(self, arr: List[int], target: int) -> int: n = len(arr) res = n + 1
pre = {}
# make sure the sub array start from 0 can be visited pre[0] = -1 dp = [float('inf')] * n
p = 0 for i, a inenumerate(arr): # p is the sum from idex 0 to i p += a dp[i] = dp[i - 1]
# if p - target in pre then target = p - pre which is a sub array # the sum eqaul to target if (p - target) in pre: cur = i - pre[p - target] # dp[pre[p - target]] != float if and only if there are sub # array whose sum eqauls to the target, and it can not connect # with cur sub array because current sub array is from index # pre[p - target] # Note that: this can find all the possible pairs of sub # arrays if pre[p - target] >= 0and dp[pre[p - target]] != float('inf'): res = min(res, cur + dp[pre[p - target]]) # dp does not equal to inf anymore, only if there are sub # array whose sum equals to the target dp[i] = min(i - pre[p - target], dp[i - 1])
# the sum from index 0 to i is p pre[p] = i return -1if res == n + 1else res
8.5. Minimum One Bit Operations to Make Integers Zero [2022-06-27]
classSolution: defminimumOneBitOperations(self, n): dp1 = [0for _ inrange(32)] #dp1[i] 表示 仅第 i 位 为 1 时 将 第 i 位变为 0 的最小修改次数 res = 0 dp1[0] = 1 for i inrange(1,32): dp1[i] = dp1[i - 1] + 1 + dp1[i - 1] f = True # 1. 0 变位仅i位为1的过程中,其后每一位都需要经历若干次从0到1,再从1到0的变化 # 2. 其后位中若原本就为1,则不会经历第一次从0到1的变化,因为它本身就是1 # 所以若把第i位从1变为0,记为dp[i],是多记录了,因为其后有1 # 所以如果其后遇到1的要减去。但是减去的话又多减了,因为其后还有1,所以又加上 for i inrange(31, -1, -1): if n >> i & 1: if f: res += dp1[i] f = False else: res -= dp1[i] f = True return res
8.6. The number of palindromes
Given a string return the number of the palindromes. The substrings are regarded
as different strings if they are start and end at different position.
classSolution: defcountSubstrings(self, s: str) -> int: n = len(s) res = [[Falsefor _ inrange(n)] for _ inrange(n)] # if n == 0, there are 0 palindromes. # if n == 1, there are 1 palindromes. ifnot n or n == 1: return n ans = n
for i inrange(n): res[0][i] = True
for i inrange(n - 1): res[1][i] = s[i] == s[i + 1] if res[1][i]: ans += 1 # if n == 2 it will not enter the following circle. # if n > 2 it will contnue to caculate palindromes whose length is larger than 2 for l inrange(2, n): for st inrange(n - l): res[l][st] = res[l - 2][st + 1] and s[st] == s[st + l] if res[l][st]: ans += 1 return ans
classSolution(object): defknightDialer(self, N): MOD = 10**9 + 7 # From 0 can reach 4 and 6 # From 1 can reach 6 and 8 moves = [[4,6],[6,8],[7,9],[4,8],[3,9,0],[], [1,7,0],[2,6],[1,3],[2,4]]
# There is dp[i]==1 ways to reach i by one step dp = [1] * 10 for hops inrange(N-1): dp2 = [0] * 10 for node, count inenumerate(dp): # There are count way to reach node by hops + 1 steps for nei in moves[node]: dp2[nei] += count dp2[nei] %= MOD # There are dp2[nei] way to reach nei by hops + 2 steps dp = dp2 returnsum(dp) % MOD
classSolution: defaddInList(self , head1: ListNode, head2: ListNode) -> ListNode: # write code here defreverse(h): ifnot h ornot h.next: return h head = h h = h.next head.next = None while h: cur = h h = h.next cur.next = head head = cur return head head1 = reverse(head1) head2 = reverse(head2) add = 0 ans = None while head1 or head2 or add: a = 0 b = 0 if head1: a = head1.val head1 = head1.next if head2: b = head2.val head2 = head2.next s = a + b + add add = s // 10 cur = ListNode(s % 10) if ans: cur.next = ans ans = cur return ans
classSolution: defreverseList(self, head: ListNode) -> ListNode: ifnot head ornot head.next: return head cur = head.next start = head # head is the last node start.next = None while cur: next_cur = cur.next cur.next = start start = cur cur = next_cur return start
9.7. Reverse Nodes in K-Group [2022-06-10]
Given the head of a linked list, reverse the nodes of the list k at a time and
return the modified list.
classSolution: # reverse a link node, the length is k defreverse(self, head: ListNode, tail: ListNode, k): current = head crop = head.next for i inrange(k - 1): follow = crop.next crop.next = current current = crop crop = follow return current, head
# while the end has next, check if it has k nodes followed while end.next: start = end.next # check if followed k nodes for i inrange(k): end = end.next # do not have k nodes followed, then do not reverse # and also the link node have been done, and return. ifnot end: return dump.next
# if have k nodes followed follow = end.next # reverse the k nodes and return the reversed start and end r_start, r_end = self.reverse(start, end, k) # connect the reversed k nodes with the original nodes current.next = r_start r_end.next = follow current = r_end end = current # the length of the link node is a multiple of k, and end.next is None, return return dump.next
ListNode* reverseKGroup(ListNode* head, int k){ ListNode* hair = newListNode(0); hair->next = head; ListNode* pre = hair;
while (head) { ListNode* tail = pre; // 查看剩余部分长度是否大于等于 k for (int i = 0; i < k; ++i) { tail = tail->next; if (!tail) { return hair->next; } } ListNode* nex = tail->next; // 这里是 C++17 的写法,也可以写成 // pair<ListNode*, ListNode*> result = myReverse(head, tail); // head = result.first; // tail = result.second; tie(head, tail) = myReverse(head, tail); // 把子链表重新接回原链表 pre->next = head; tail->next = nex; pre = tail; head = tail->next; }
return hair->next; } };
9.8. Palindrome Linked List
Given the head of a singly linked list, return true if it is a Palindrome.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution: defisPalindrome(self, head: ListNode) -> bool: res = [] ifnot head: returnTrue num = 0 first = head while first.next: res.append(first.val) num += 1# count the length of the linked list first = first.next res.append(first.val) # store all the node value for i inrange(num // 2 + 1): # does not need to check all the nodes if res[i] != res[num - i]: returnFalse returnTrue
If one want only use O(n) time and O(1) storage, must reverse the last half of
the linked list.
special = set("!@#$%^&*()-+") pre_char = '' for i in password: if i == pre_char: contain_twosame = True pre_char = i ifnot contain_lower and i.islower(): contain_lower = True continue ifnot contain_upper and i.isupper(): contain_upper = True continue ifnot contain_number and i.isdigit(): contain_number = True continue ifnot contain_special and i in special: contain_special = True continue return if_length and contain_lower and contain_upper and contain_number and contain_special andnot contain_twosame
10.3. Minimum Changes to Make Alternating Binary String
You are given a string s consisting only of the characters 0 and 1. In one
operation, you can change any 0 to 1 or vice versa.
The string is called alternating if no two adjacent characters are equal. Return
the minimum number of operations needed to make s alternating.
1 2 3 4 5 6 7 8 9 10 11
classSolution: defminOperations(self, s: str) -> int: n = len(s) # The ans is the operation needed to turn s into `010101` ans = 0 for i inrange(n): if i % 2and s[i] != "1": ans += 1 ifnot i % 2and s[i] != "0": ans += 1 returnmin(ans, n - ans)
classSolution: defminNumberInRotateArray(self , rotateArray: List[int]) -> int: # write code here n = len(rotateArray) left = 0 right = n - 1 while left < right: mid = (left + right) // 2 if rotateArray[mid] > rotateArray[right]: left = mid + 1 else: right -= 1 return rotateArray[left]
classSolution: defInversePairs(self , data: List[int]) -> int: # write code here res = data n = len(res) ans = [0] defdivide(left, right): if left >= right: return mid = (left + right) // 2 divide(left, mid) divide(mid + 1, right) merge(left, mid, right) defmerge(left, mid, right): l = left r = mid + 1 tmp = [] while l <= mid and r <= right: if res[l] > res[r]: tmp.append(res[r]) r += 1 ans[0] += mid -l + 1 ans[0] %= 1000000007 else: tmp.append(res[l]) l += 1 while l <= mid: tmp.append(res[l]) l += 1 while r <= right: tmp.append(res[r]) r += 1 for i inrange(left, right + 1): res[i] = tmp.pop(0) divide(0, n -1) return ans[0]
curs = [ [0, grid[start[0]][start[1]], start[0], start[1]] ]
# gird set to 0 is to avoid visiting a coordinate for multiple time. # The position to set the grid to be 0 is important. # in this example, the price of a coordinate is set to 0 when it is visited by curs. # also can set the price to be 0, when it is checked if within the price range. # However, this is time expensive, for a position maybe append to curs many times before it is checked. # It is the best to set the price to be 0, once it is visited by curs. The curs will not visits it again. grid[start[0]][start[1]] = 0
r = len(grid) c = len(grid[0])
dirctions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
while curs: cur = curs.pop(0) cur_step = cur[0] cur_price = cur[1] cur_row = cur[2] cur_cln = cur[3]
if pricing[0] <= cur_price <= pricing[1]: res.append(cur)
Given an integer array nums, recorder it such that
nums[0] < nums[1] > nums[2] < nums[3] > .... You may assume the input array
always has a valid answer.
classSolution: defwiggleSort(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ res = [] for i in nums: res.append(i) res.sort() n = len(nums) # Because the smaller number is always filled first, # let len(smaller numbers) - len(larger numbers) == 1 # if the len(nums) is odd. # if n is even, the small half from 0 to n // 2 - 1 # the large half from n // 2 to n - 1 # if n is odd, small number from 0 to n // 2 # large number from n // 2 + 1 to n - 1, # Thus, no matter n is odd or even, small number from 0 to # (n + 1) // 2 - 1, large number from (n + 1) // 2 to n - 1 half = (n + 1) // 2 # to avoid that the last small number is equal to the first large # number, fill the small number from *last* to first, # also, fill the large number from last to *first* # ** means that the number should try to be apart.
# if n is even, half * 2 == n # if n is odd, half * 2 == n + 1 for i inrange(half): nums[2 * i] = res[half - 1 -i] # len(large number) is smaller than len(small number), # thus, the when i = half -1, maybe no large number anymore try: nums[2 * i + 1] = res[n - 1 - i] except: pass
11.8. Rank Teams by Votes
In a special ranking system, each voter gives a rank from highest to lowest to
all teams participated in the competition, e.g., one gives ABC, one gives
BCA.
The ordering of teams is decided by who received the most position-one votes. If
A received the most 1-st place Then A is the first. If B received the same
first place as A then compare the number of second place they received. If A
and B received all the places the same number then ordered them by their
letter, i.e., A is in front of B.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defrankTeams(self, votes: List[str]) -> str: n = len(votes[0]) # initialization of a hash map, the default value is list [0, 0, ..., 0] # NOTE: How to set defaultdict by lambda without input, it is indeed a function factory. ranking = collections.defaultdict(lambda: [0] * n) # count the vote situation for each team, vid is the name of teams. for vote in votes: for i, vid inenumerate(vote): ranking[vid][i] += 1
# result is a list, e.g., [('A', [5, 0, 0]), ('B', [0, 2, 3]), ('C', [0, 3, 2])] result = list(ranking.items()) # sort the order of letter -ord(x[0]) is regard as the last criterion result.sort(key=lambda x: (x[1], -ord(x[0])), reverse=True) # return the ordered vid return"".join([vid for vid, rank in result])
11.9. Number Game
Give a list of numbers. You can + 1 or - 1 at position i which is regarded
as one operator at position i. Please return the minimum operators for
position i to make the list of numbers satisfying
nums[a] + 1 == nums[a + 1], 0 <= a <= i. The original topic is
here.
11.9.1. Analysis
To satisfying nums[a] + 1 == nums[a + 1], we do not know which number it is
for position i which makes the operators minimum.
Thus we can transform this problem, we make nums[a] = nums[a] - a. Then we
only need to make each position of the nums all equal to the same number. Then
the minimum way is to set the number as the median number of nums.
NOTE: it is the median number, not the mean value. If the
length of the list is even then the median is the mean of the middle two
numbers.
It is easy to prove that the mean value can not bring the minimum operators. For
examples, for list [1, 3, 8] the mean value is 4 and it needs
3 + 1 + 4 = 8 operators to make the list into [4, 4, 4]. The median is 3
and it needs only 2 + 0 + 5 = 7 operators to make the list into [3, 3, 3].
The reason for why it is the median.
Let s be the value that each position will reach and m be the median. If s
is large than m, then #(nums[i] > s) < #(nums[i] < s). If set s = s - 1,
nums[i] will add 1 operator if nums[i] > s and nums[i] will decrease 1
operator if nums[i] < s. For #(nums[i] > s) < #(nums[i] < s), the total
number of operators will decrease. It will always decrease until s == m, i.e.,
#(nums[i] > s) = #(nums[i] < s).
defadd(self, num: int) -> None: # if #small == #large then put the num in large # How to push it in large. # NOTE: not put it in large directly, find the largest value then put it in to the large. # This ensure that large is always larger than small. # #small always smaller than #large and only larger than 1 iflen(self.small) == len(self.large): leftMax = -heappushpop(self.small, -num) heappush(self.large, leftMax) self.leftSum += num - leftMax self.rightSum += leftMax eliflen(self.small) < len(self.large): rightMin = heappushpop(self.large, num) heappush(self.small, -rightMin) self.leftSum += rightMin self.rightSum += num - rightMin
defgetMedian(self) -> float: # self.large[0] is the smallest value in large # -self.small[0] is the largest value in small # get the median if the length is odd, else the mean of the two middle numbers iflen(self.small) == len(self.large): return (self.large[0] - self.small[0]) / 2 else: return self.large[0]
defgetDiffSum(self) -> float: median = self.getMedian() return self.rightSum - len(self.large) * median + len(self.small) * median - self.leftSum
classSolution: defnumsGame(self, nums: List[int]) -> List[int]: MOD = int(1e9 + 7) res = [] medianFinder = MedianFinder() for i inrange(len(nums)): normalized = nums[i] - i medianFinder.add(normalized) res.append(int(medianFinder.getDiffSum() % MOD)) return res
classSolution: defFind(self , target: int, array: List[List[int]]) -> bool: # write code here deffind_mid(ma, target): # return the idx, whose left is all smaller than # target and right is larger or equal to the target left = 0 right = len(ma) - 1 while left < right: mid = (left + right) // 2 if ma[mid] < target: left = mid + 1 else: # ma[mid] => target right = mid return right for i in array: idx = find_mid(i, target) if0 <= idx < len(i) and i[idx] == target: returnTrue returnFalse
classSolution: deftimeRequiredToBuy(self, tickets: List[int], k: int) -> int: res = 0 target = tickets[k] n = len(tickets) for i inrange(n): if i <= k: res += min(tickets[i], target) else: res += min(tickets[i], target - 1) return res
13.3. Form Array by Concatenating Sub-arrays in Another Array [2022-07-09]
idx = 0 defif_find(cur_r, idx): num_column = len(groups[cur_r]) for i inrange(idx, n - num_column + 1): if groups[cur_r] == nums[i: i + num_column]: return i + num_column return -1
for i inrange(num_row): idx = if_find(i, idx) if idx == -1: returnFalse returnTrue
classSolution: deflongestDecomposition(self, text: str) -> int: defget_sub_str(s): n = len(s) for i inrange(1 , n // 2 + 1): if s[ : i] == s[n - i : ]: return i return0
ans = 0 while text: cur_sub_length = get_sub_str(text) ifnot cur_sub_length: return ans + 1
text_length = len(text) text = text[cur_sub_length : text_length - cur_sub_length] ans += 2 return ans
classSolution: deferaseOverlapIntervals(self, intervals: List[List[int]]) -> int: ifnot intervals: return0 # sort by the end position intervals.sort(key=lambda x: x[1]) n = len(intervals) right = intervals[0][1] ans = 1
for i inrange(1, n): # do not overlap the previse interval add it # this is equal to reomve the interval when it is overlap with # the previse one # it is the right way, because when overlap, the interval must be # removed or remove at least one of added intervals and the right # will get larger when remove the added intervals. if intervals[i][0] >= right: ans += 1 right = intervals[i][1] return n - ans
classSolution: defnumOfStrings(self, patterns: List[str], word: str) -> int: ans = 0 n = len(word) defcheck(pa): m = len(pa) for i inrange(n - m + 1): if word[i : i + m] == pa: return1 return0
for pa in patterns: ans += check(pa) return ans
14.4. Coordinate with Maximum Network Quality [2022-05-10]
An array of network towers towers is given, where
towers[i]=[xi,yi,qi]. xi and yi are the integral coordinates of
the network tower location and qi is the network quality factor. The network
quality of towers[i] at (x,y) is qi/(1+d) where
d=(x−xi)2+(y−yi)2.
You are also given an integer radius. All the tower is not reachable if and
only if d > radius.
The network quality of a location is the sum of network qualities from all
towers. Return the location with the maximum network quality.
If there are multiple coordinates with the same network quality, return the
lexicographically minimum non-negative coordinate.
Constraints:
1 <= towers.length <= 50
towers[i].length == 3
0 <= xi, yi, qi <=50
1 <= radius <= 50
14.4.1. Analysis
For 0 <= xi, yi, qi <=50, if x or y is large than 51, it can not be the
answer. All the network quality will be stronger when x or y is smaller. Thus,
we do only need to search within [0, 51].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import math classSolution: defbestCoordinate(self, towers: List[List[int]], radius: int) -> List[int]: max_signal, x, y = 0, 0, 0 # search from small coordinate to large then we will get the small coordinate first for i inrange(51): for j inrange(51): signal_ij = 0 for tower in towers: delta_x, delta_y = tower[0] - i, tower[1] - j d = math.sqrt(delta_x * delta_x + delta_y * delta_y) # if > radius no quality if d > radius: continue # use floor signal_ij += math.floor(tower[2] / (1 + d)) if signal_ij > max_signal: max_signal, x, y = signal_ij, i, j return [x, y]
classSolution: defisValid(self, s: str) -> bool: dic = {')' : '(', '}' : '{', ']' : '[' } res = [] for i in s: if i in dic: ifnot res: returnFalse cur = res.pop() if cur != dic[i]: returnFalse else: res.append(i) if res: returnFalse returnTrue
classSolution: defminNumberDisappeared(self , nums: List[int]) -> int: n = len(nums) #遍历数组 for i inrange(n): #数全部记为n+1 if nums[i] <= 0: nums[i] = n + 1 for i inrange(n): #对于1-n中的数字 ifabs(nums[i]) <= n: #这个数字的下标标记为负数 nums[abs(nums[i]) - 1] = -1 * abs(nums[abs(nums[i]) - 1]) for i inrange(n): #找到第一个元素不为负数的下标 if nums[i] > 0: return i + 1 return n + 1
17.2. Find All Numbers Disappeared in an Array [2022-10-12]
classSolution: deffindDisappearedNumbers(self, nums: List[int]) -> List[int]: n = len(nums) for i in nums: x = i % n nums[x] += n res = [] for i inrange(n): if nums[i] <= n: if i == 0: res.append(n) else: res.append(i) return res
17.3. Rearrange Characters to Make Target String [2022-07-27]
classSolution: defrearrangeCharacters(self, s: str, target: str) -> int: res = {} for i in target: if i in res: res[i] += 1 else: res[i] = 1 ans = {} for i in s: if i in res: if i in ans: ans[i] += 1 else: ans[i] = 1
out = float('inf') for i in res: ifnot i in ans: out = 0 break else: out = min(out, ans[i] // res[i]) return out
classSolution: defdisplayTable(self, orders: List[List[str]]) -> List[List[str]]: # use dict to quickly find the food tables = defaultdict(lambda: defaultdict(int)) food_set = set() for _, table, food in orders: food_set.add(food) tables[table][food] += 1
res = [] # sort the food food_list = sorted(food_set) res.append(['Table']+food_list) for table insorted(tables.keys(),key=int): res.append([table] + [str(tables[table][item]) for item in food_list]) return res
17.6. Minimum Cost to Set Cooking Time [2022-06-29]
classSolution: defintersect(self, nums1: List[int], nums2: List[int]) -> List[int]: ans = [] res1 = defaultdict(lambda : 0) res2 = defaultdict(lambda : 0) for i in nums1: res1[i] += 1 for i in nums2: res2[i] += 1 for key in res1: if key in res2: num = min(res1[key], res2[key]) ans += [key] * num return ans
17.9. Check if There is a Valid Path in a Grid [2022-06-21]
defreach(cur): pre = [0, 0] while cur != [0, 0] and0 <= cur[0] < n and0 <= cur[1] < m: nex1 = to_position(cur, res[grid[cur[0]][cur[1]]][0]) nex2 = to_position(cur, res[grid[cur[0]][cur[1]]][1]) if nex1 != pre and nex2 != pre: returnFalse # be careful about the position of checking if reach the destination # can not be after `cur = nex`, because it can be reachable only # checked nex1 or nex2 == pre if cur == [n - 1, m - 1]: returnTrue nex = nex1 if nex1 != pre else nex2 pre = cur cur = nex returnFalse start = [0, 0] cur1 = to_position(start, res[grid[0][0]][0]) cur2 = to_position(start, res[grid[0][0]][1]) return reach(cur1) or reach(cur2)
classSolution: defsmallestDistancePair(self, nums: List[int], k: int) -> int: defcount(mid: int) -> int: # count the pairs whose distance smaller and equil to mid cnt = 0 for j, num inenumerate(nums): # when num is the larger one in the pair # the number in some position could be the # smaller one, it must larger than num - mid i = bisect_left(nums, num - mid, 0, j) cnt += j - i return cnt
nums.sort()
# The answer must be in range(0, nums[-1] - nums[0]) # when pick a number in the range, we count the pair of numbers # whose distance is smaller or equal than it.
# for example, if number 5, 6, 7, 8 have count k - 1, k, k, k +1 # the answer will be 6, 5 has k - 1 pairs smaller or equal # 6 has k, thus will have pairs distance euqal to 6, and it is # the top-k smallest distance. # there are no pair whose distance is 7
# if number 5, 6, 7 have count k - 10, k + 10, k + 20 # the answer is 6, there is 20 pairs whose distace is 6, and # and the top-k smallest distance is in them.
# if the number nums[-1] - nums[0] - 1 has n counts and k > n # then k will be nums[-1] - nums[0] # thus, we need to use bisect_left and do not need to exame # nums[-1] - nums[0] return bisect_left(range(nums[-1] - nums[0]), k, key=count)
17.11. Maximum Number of Visible Points [2022-06-19]
classSolution: defvisiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int: sameCnt = 0 polarDegrees = [] for p in points: if p == location: sameCnt += 1 else: # obain all the angles the range is (-pi, pi] polarDegrees.append(atan2(p[1] - location[1], p[0] - location[0]))
polarDegrees.sort()
n = len(polarDegrees) # and 2 pi, the -pi will changed to pi, and thus -pi and pi # will be adjoined to each other # deg and deg + 2pi are both counted only if the angle is 2pi polarDegrees += [deg + 2 * pi for deg in polarDegrees]
# change the degree into pi degree = angle * pi / 180 # bisect_right/bisect_left require from bisect import xxxx # both bisect_right or bisect_left return the index that the val # placed in to the array and keeps the array ranked.
# when there are numbers equal to val bisect_right places the val to the right # side of the equaled numbers, thus the returned value is the number of digits # smaller and equil to val in the array
# bisect_left places the val to the left side of the equaled numbers. Thus the # returned value is the number of digits smaller to the val in the array
# here bisect_right should be used maxCnt = max((bisect_right(polarDegrees, polarDegrees[i] + degree) - i for i inrange(n)), default=0) return maxCnt + sameCnt
17.12. Number of Different Integers in a String [2022-06-17]
classSolution: defnumDifferentIntegers(self, word: str) -> int: res = set() cur = 0 word += 'a' flag = False for i in word: if i.isdigit(): flag = True cur = cur * 10 + int(i) else: if flag: res.add(cur) cur = 0 flag = False returnlen(res)
classSolution: deffindLongestChain(self, pairs: List[List[int]]) -> int: res = sorted(pairs, key = lambda a: a[1]) ans = [res[0]] n = len(res) for i inrange(1, n): if ans[-1][-1] < res[i][0]: ans.append(res[i]) returnlen(ans)
classSolution: defexchangeBits(self, num: int) -> int: num_bin = bin(num) n = len(num_bin) res = '' start = 2 if n % 2: res += '10' start = 3 for i inrange(start, n, 2): res += num_bin[i + 1] res += num_bin[i] returnint(res, 2)
17.16. The First Char which Only Appears once [2022-06-16]
classSolution: deffirstUniqChar(self, s: str) -> str: res = collections.defaultdict(lambda: [0, 1]) for idx, c inenumerate(s): ifnot c in res: res[c][0] = idx else: res[c][1] += 1 ans = " " min_idx = len(s) for i in res: if res[i][1] == 1and res[i][0] < min_idx: min_idx = res[i][0] ans = i return ans
17.17. The Gas Station
There are n stations along a circular route, where the amount of gas at the
ith station is gas[i].
A car costs cost[i] of gas to travel from the ith station to its next
(i+1)th station.
Can the car run a circle. If can, return the start station. If not, return -1.
If there exists a solution, it is guaranteed to be the unique.
classSolution: defcanCompleteCircuit(self, gas: List[int], cost: List[int]) -> int n = len(gas) res = [0] * n # a car pass station i, it can get gas[i] and cost # cost[i]. Thus gets gas[i] - cost[i]. # ifin station i, gas[i] - cost[i] >= 0, it can # arrive the next station. # after arrive the next station, and gets the station # if the remain >= 0 it can gets the nextnext station. for i inrange(n): res[i] = gas[i] - cost[i] first = 0 second = 0 sum_ = res[0] key = False # second represents the station the car already getting. # first represents the starting station. # sum_ represents if the car can get the next staion. # if sum_ >= 0, it can, else, it can not. whileTrue: if sum_ >= 0: second += 1 if second == n: second = 0 key = True if key and second == first: return first sum_ += res[second] else: sum_ -= res[first] first += 1 # from 0 to n, first do not find an answer, return -1. if first == n: return -1 else: if first > second: second += 1 sum_ += res[second
Consider this, if y is the first station that the car can not arrive from x.
That is to say ∑i=yxres[i]<0. For a station z between x and y. It
can arrive z from x, which means the sum >0. Then from z to y, the sum is
definitely <0. It can not arrive y from z.
Thus, if a car can not arrive y from x, it can not arrive y from any station
between x and y. It is no need to search such stations.
classSolution: defcanCompleteCircuit(self, gas: List[int], cost: List[int]) -> int: n = len(gas) res = [0] * n for i inrange(n): res[i] = gas[i] - cost[i] first = 0 second = 0 sum_ = res[0] key = False whileTrue: if sum_ >= 0: second += 1 if second == n: second = 0 key = True if key and second == first: return first sum_ += res[second] else: # if can not arrive second + 1, then # starting from second + 1 second += 1 first = second # if the new starting point equal or bigger than # n, first move from 0 to n fails to find. # if key is True, second + 1 is actually larger than # n, first move from 0 to n fails to find. if first == n or key: return -1 sum_ = res[first]
17.18. Maximum Number of Tasks You Can Assign [2022-05-11]
classSolution: defmaxTaskAssign(self, tasks: List[int], workers: List[int], pills: int, strength: int) -> int: tasks.sort() workers.sort() n = len(tasks) m = len(workers) ans = 0 j = 0 for i inrange(m): if j < n: # A new worker waiting for task if workers[i] >= tasks[j]: ans += 1 # the task has been assigned, consider the next task j += 1 else: # if there is pills avaliable if pills and workers[i] + strength >= tasks[j]: # use this pill pills -= 1 ans += 1 j += 1 return ans
This code prefers to use small strength workers, which is wrong. When the
workers can do k tasks, it must be the top k strength workers taking the
bottom k tasks.
classSolution: defmaxTaskAssign(self, tasks, workers, pills, strength): n, m = len(tasks), len(workers) tasks.sort() workers.sort()
defcheck(mid: int) -> bool: p = pills # the workers needed to be check ws = SortedList(workers[m - mid:]) # tasks from large to small for i inrange(mid - 1, -1, -1): if ws[-1] >= tasks[i]: # tasks[i] is assigned to ws[-1] ws.pop() else: if p == 0: # if does not have pills anymore returnFalse # has pills # Note: find the smallest worker can take the task by pill rep = ws.bisect_left(tasks[i] - strength) if rep == len(ws): returnFalse p -= 1 ws.pop(rep) returnTrue
# The scope of k needed to be checked if 1 checked false, answer is 0 # if right = min(m, n) checked true, answer is right left, right, ans = 1, min(m, n), 0 while left <= right: mid = (left + right) // 2 if check(mid): # if mid is true, then ans is larger than mid # find it in [mid + 1, right] ans = mid left = mid + 1 else: # if mid is false, then ans is smaller than mid # find it in [left, mid - 1] right = mid - 1