Lontananza
less than 1 minute read
Memory images, once they are fixed in words, are erased.
嗨嗨嗨!!勋章来咯!!

01 Maximum Number of Achievable Transfer RequestsHard DFS
You are given an integer array
cookies, wherecookies[i]denotes the number of cookies in theithbag. You are also given an integerkthat denotes the number of children to distribute all the bags of cookies to. All the cookies in the same bag must go to the same child and cannot be split up.The unfairness of a distribution is defined as the maximum total cookies obtained by a single child in the distribution. Return the minimum unfairness of all distributions.
A counterexample where Greedy fails can be easily constructed. We observe the constraint that 2 <= cookies.length <= 8, hence the clue of using DFS.
The idea is to iterate the cookies. Each time we distribute this cookies to any possible children, and go to the next layer of DFS.
class Solution:
    def distributeCookies(self, cookies: List[int], k: int) -> int:
		ans = sum(cookies)
        
        def searchCandies(i, children, current_max):
            nonlocal ans
            # children records the current candies each child has
            # current_max records the local answer
            if i>=len(cookies):
                ans = min(ans, current_max)
                return
            for child_id in range(len(children)):
                # we assign the cookie to child i
                if children[child_id]+cookies[i] >= ans: continue
                children[child_id] += cookies[i]
                searchCandies(i+1, children,  
                max(current_max, children[child_id]))
                children[child_id] -= cookies[i]
        searchCandies(0, [0]*k, 0)
        return ans
if children[child_id]+cookies[i] >= ans: continue
The ans is an existing local solution. So there is no point to do further DFS if the current distribution plan has a larger unfairness.
nonlocalIf you delete nonlocal in code, an error emerges: UnboundLocalError: local variable 'ans' referenced before assignment. This is because Python does not know the ans variable in our searchCandies function. It will consider it as a local variable, hence creating a new ans inside the function - this explains the description of this error.
There are two ways to get around this. First is this nonlocal argument. The second is to move ans to the Solution class. i.e. define ans (and use it) in the form of self.ans.
An idea is to have a better starting point. We use heap to formulate a greedy solution: Each time we assign a cookie to the child with least number of cookies. This has constant time cost (because the number of cookies smaller than 8), but will give a very nice upper bound of solution, which cuts lots of leaves in the later DFS.
Simply replace the ans = sum(cookies) with this:
cookies.sort(reverse = True)
heap = [0] * k
for i in cookies:
	currentLeastChild = heapq.heappop(heap)
	currentLeastChild += i
	heapq.heappush(heap,currentLeastChild)
ans = max(heap)
sort is again optional, but basically costs no time.02 Fair Distribution of CookiesHard DFS Divide and Conquer
bitMask to search request casesclass Solution:
  def maximumRequests(self, n: int, requests: List[List[int]]) -> int:
      def bitmaskToBool(n):
          bitsOn = []
          while n:
              bitsOn.append(n%2==1)
              n = n//2
          return(bitsOn)
      ans = 0
      for mask in range(1, (1<<len(requests))):
          bitsOn = bitmaskToBool(mask)
          pathLength = sum(bitsOn)
          if pathLength<=ans: continue
          indeg = [0 for _ in range(n)]
          for i in range(len(bitsOn)):
              if not bitsOn[i]: continue
              req = requests[i]
              indeg[req[0]]-=1
              indeg[req[1]]+=1
          if all([x==0 for x in indeg]):
              ans = max(ans, pathLength)
      return(ans)
03 Buddy StringsEasy Silly
纯笨b摆烂天把所有情况想明白就完事了没什么好说的题目😅.
class Solution:
    def buddyStrings(self, s: str, goal: str) -> bool:
        if len(s)!=len(goal) or len(s)<=1: return(False)
        if len(s)==2:
            return (s[0]==goal[1] and s[1]==goal[0])
        diff = -1
        for i in range(len(s)):
            if s[i]!=goal[i]:
                if diff==-2: return(False) #two pairs differ
                if diff==-1: # no pair differs
                    diff = i
                else: # diff = i, one pair differs
                    if not(s[diff]==goal[i] and s[i]==goal[diff]):
                        return(False)
                    else:
                        diff=-2
        if diff == -1:  # all same
            return not len(set(s))==len(s)
        elif diff == -2:
            return True
        else:
            return False 
04 Single Number IIMedium Array Bit Manipulation
Use idea of XOR. The logic is a bit confusing, better take some numbers and try for yourself 🙂.
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        a, b = 0, 0
        for i in nums:
            a = (a^i) & ~b
            b = (b^i) & ~a
        return a
05 Longest Subarray of 1’s After Deleting One ElementMedium Array Greedy
Given a binary array
nums, you should delete one element from it.Return the size of the longest non-empty subarray containing only 1’s in the resulting array. Return 0 if there is no such subarray.
不是,您每天出这种题目,您图啥呢?Simply 贪心。
class Solution:
    def longestSubarray(self, nums: List[int]) -> int:
        if len(nums)==1: return(0)
        if 0 not in nums: return(len(nums)-1)
        current_max = now_len = prev_len = 0
        for i in range(len(nums)):
            if not nums[i]:
                current_max = max(current_max, prev_len + now_len)
                if i==len(nums)-1: return current_max
                
                if nums[i+1]:
                    prev_len = now_len
                    now_len = 0
                else:
                    prev_len = now_len = 0
            else:
                if now_len>current_max: current_max = now_len
                now_len+=1
        return(max(current_max, prev_len+now_len))
06 Minimum Size Subarray SumMedium Pointer Array
Given an array of positive integers
numsand a positive integertarget, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead.
普及组第一题都不敢出这么简单的级别泥🤧two pointers O(n)完事泥.
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        left = now = 0
        ans = len(nums)+1
        for i in range(len(nums)):
            now+=nums[i]
            if now>=target:
                while now-nums[left]>=target:
                    now-=nums[left]
                    left+=1
                ans = min(ans, i-left+1)
        return(0 if ans==len(nums)+1 else ans)    
07 Maximize the Confusion of an ExamMedium Pointer Greedy
A teacher is writing a test with n true/false questions, with ‘T’ denoting true and ‘F’ denoting false. He wants to confuse the students by maximizing the number of consecutive questions with the same answer (multiple trues or multiple falses in a row).
You are given a string
answerKey, whereanswerKey[i]is the original answer to the ith question. In addition, you are given an integerk, the maximum number of times you may perform the following operation:Change the answer key for any question to ‘T’ or ‘F’ (i.e., set
answerKey[i]to ‘T’ or ‘F’). Return the maximum number of consecutive ‘T’s or ‘F’s in the answer key after performing the operation at most k times.
Simple greedy. No point not exploiting all ks if possible. Simply use a pointer l to indicate the current left position. If surpassed then adjust left to the closest.
class Solution:
    def maxConsecutiveAnswers(self, answerKey: str, k: int) -> int:
        ans = 0
        for c in ['T','F']:
            l = current = count = 0
            for i in range(len(answerKey)):
                if answerKey[i]==c: count+=1 # WT replace c
                while count > k: #don't want the left
                    if answerKey[l]==c: count-=1
                    l+=1
                current = max(current, i-l+1)
            ans = max(ans,current)
        return(ans)
今天的双周赛好水啊,就跟Leetcode的服务器一样😌。
08 Put Marbles in BagsHard Greedy
You have k bags. You are given a 0-indexed integer array
weightswhereweights[i]is the weight of the ith marble. You are also given the integerk.Divide the marbles into the
kbags according to the following rules:
- No bag is empty.
- If the ith marble and jth marble are in a bag, then all marbles with an index between the ith and jth indices should also be in that same bag.
- If a bag consists of all the marbles with an index from i to j inclusively, then the cost of the bag is
weights[i] + weights[j]. The score after distributing the marbles is the sum of the costs of all the k bags.Return the difference between the maximum and minimum scores among marble distributions.
Constraints
It’s easy to think about taking a sum of neighbours and try to locate extreme situations among them. Two things to consider: 1 the boundary of arrays 2 the one-element groups. The first is easy to figure out, because in max and min cases the 0th and -1th element has to be included in the cost, so it cancel out.
For the second, take a neighbour sum (e.g. np.array(weights[1:]) + np.array(weights[:-1])). You will find out that the partition is actually bijective to taking $k-1$ elements from neighbour-sum.
Didn’t use numpy, as importing is slow, and wanna beat as many people as possible for QSD’s bizzard dignity.

class Solution:
    def putMarbles(self, weights: List[int], k: int) -> int:
        if k==1: return(0)
        neighbourSumWeights = sorted([weights[i] + weights[i+1] for i in range(len(weights)-1)])
        return(sum(neighbourSumWeights[-(k-1):])-sum(neighbourSumWeights[:(k-1)]))
09 Substring With Largest VarianceHard DP
Finally an interesting question. Good for Leetcode 😌.
The variance of a string is defined as the largest difference between the number of occurrences of any 2 characters present in the string. Note the two characters may or may not be the same.
Given a string
sconsisting of lowercase English letters only, return the largest variance possible among all substrings ofs.A substring is a contiguous sequence of characters within a string.
Constraints $1 \leq s.length \leq 10^4$
Classical DP question (as the data constraint suggests). The first idea is to 1. iterate the two letters among all letters. 2. count the occurrence among all possible substrings of s.
This is clearly TLE. Then DP naturally comes up to skip unncessary sub-problems during Step 2. The difference of occurrence between two letters is then linked to Kadane’s Algorithm (The classical $O(n)$ solution to Largest Sum Contiguous Subarray problem).
One problem remains is the situation of $abb$, which, as we reset the difference to 0 to find the optimal solution in Kadane, results in answer
0. The convenient solution is to calculate again fors[::-1]. (Further optimisation for this clearly exists as the overlapping of calculation, but only provides constant optimisation for time complexity)
time complexity $26^2*\text{len}(s)$
class Solution:
    def largestVariance(self, s: str) -> int:
        letters = set(s)
        if len(letters)==1: return(0)
        ans = 0
        for a in letters:
            for b in letters:
                if a==b: continue
                for sSs in [s,s[::-1]]:
                    curMax = countA = countB = 0
                    for letter in sSs:
                        if letter not in [a,b]: continue
                        countA+= (letter==a)
                        countB+= (letter==b)
                        if countA<countB: countA = countB = 0
                        if countA*countB: curMax = max(curMax, countA-countB)
                    ans = max(ans, curMax)
        return(ans)
10 Minium Depth of Binary TreeEasy Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
水,注意number of nodes可以是0。下一题。
# 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
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        ans = 0
        queue = [root]
        ne = root
        while queue:
            now = queue.pop(0)
            if now==ne: ans+=1
            if now.left==None and now.right==None: return(ans)
            if now.left: queue.append(now.left)
            if now.right: queue.append(now.right)
            if now==ne:
                if now.left:
                    ne=now.left
                else:
                    ne=now.right
11 All Nodes Distance K in Binary TreeMedium Tree BFS
Given the root of a binary tree, the value of a target node
target, and an integerk, return an array of the values of all nodes that have a distancekfrom the target node.
Classic BFS. Simple variation of yesterday’s question. Beat 8% in time, because just finished Mission Impossible and too exhuasted to optimise the algo.
class Solution:
    def distanceK(self, root: TreeNode, target: TreeNode, k: int) -> List[int]:
        queue = [root]
        fathers = {root: None}
        distance = [0 for _ in range(1000)]
        while queue:
            now = queue.pop(0)
            if now.left:
                queue.append(now.left)
                fathers[now.left] = now
            if now.right:
                queue.append(now.right)
                fathers[now.right] = now
        ans = []
        queue = [target]
        hasVisited = []
        distance[target.val] = 0
        while queue:
            now = queue.pop(0)
            hasVisited.append(now.val)
            if distance[now.val]==k: ans.append(now.val)
            for x in [now.left,now.right,fathers[now]]:
                if x==None: continue
                if x.val in hasVisited: continue
                queue.append(x)
                distance[x.val] = distance[now.val] + 1
        return(ans)
12 Find Eventual Safe StatesMedium DFS
There is a directed graph of n nodes with each node labeled from 0 to n - 1. The graph is represented by a 0-indexed 2D integer array
graphwheregraph[i]is an integer array of nodes adjacent to node i, meaning there is an edge from node i to each node ingraph[i].A node is a terminal node if there are no outgoing edges. A node is a safe node if every possible path starting from that node leads to a terminal node (or another safe node).
Return an array containing all the safe nodes of the graph. The answer should be sorted in ascending order.
Classic DFS question. Nothing much to explain.
class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        n = len(graph)
        safe, ans = {}, []
        def dfs(now: int):
            if now in safe: return safe[now]
            safe[now] = False
            for adj in graph[now]:
                if dfs(adj)==False: return(safe[now])
            safe[now] = True
            return safe[now]
        for i in range(n):
            if dfs(i): ans.append(i)
        return(ans)
13 Course ScheduleMedium Topological Sort DFS
There are a total of
numCoursescourses you have to take, labeled from 0 tonumCourses-1. You are given an arrayprerequisiteswhereprerequisites[i] = [ai, bi]indicates that you must take coursebifirst if you want to take courseai.
- For example, the pair $[0, 1]$, indicates that to take course 0 you have to first take course 1.
Return
trueif you can finish all courses. Otherwise, returnfalse.
class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        adj = [[] for _ in range(numCourses)]
        for end, start in prerequisites:
            # b first before a, so b->a
            adj[start].append(end)
        status = [0] * numCourses
        #status: 0 not yet, -1 processing, 1 done
        def isCycle(now):
            # processing(-1): cycle; done(1): nope
            if status[now]: return status[now]==-1
            status[now] = -1
            for v in adj[now]:
                if isCycle(v): return True
            status[now] = 1
            return False
        for v in range(numCourses):
            if isCycle(v): return False
        return True
14 Longest Arithmetic Subsequence of Given DifferenceMedium Greedy
Given an integer array
arrand an integerdifference, return the length of the longest subsequence inarrwhich is an arithmetic sequence such that the difference between adjacent elements in the subsequence equalsdifference.A subsequence is a sequence that can be derived from arr by deleting some or no elements without changing the order of the remaining elements.
straightforward greedy. Use dict to collect nums.
class Solution:
    def longestSubsequence(self, arr: List[int], difference: int) -> int:
        prevLoc, ans = {}, 1
        for i in arr:
            if i-difference in prevLoc:
                cur = prevLoc[i-difference] + 1
                if i in prevLoc:
                    prevLoc[i] = max(prevLoc[i], cur)
                else:
                    prevLoc[i] = cur
            else:
                if i not in prevLoc: prevLoc[i] = 1
            if prevLoc[i]>ans: ans=prevLoc[i]
        return ans
15 Maximum Number of Events That Can Be Attended IIHard DP
You are given an array of events where
events[i]=[startDayi, endDayi, valuei]. The ith event starts atstartDayiand ends atendDayi, and if you attend this event, you will receive a value ofvaluei. You are also given an integerkwhich represents the maximum number of events you can attend.You can only attend one event at a time. If you choose to attend an event, you must attend the entire event. Note that the end day is inclusive: that is, you cannot attend two events where one of them starts and the other ends on the same day.
Return the maximum sum of values that you can receive by attending events.
Constraints $1\leq k * events.length \leq 10^6$
一眼DP。然后把数据量看成1≤k≤events.length≤10^6,然后想了一年啊这怎么可能$O(n)$做啊啊啊啊,然后发现原来就是简单DP。 $dp[i][j]$前i件选j件的max。
class Solution:
    def maxValue(self, events: List[List[int]], k: int) -> int:
        events.sort(key=lambda x: x[1])
        terminates = [x[1] for x in events]
        @lru_cache(None)
        def dp(i, j):
            if i<0 or j==0: return 0
            startat = bisect.bisect_left(terminates, events[i][0])-1
            return max(dp(startat,j-1)+events[i][2], dp(i-1,j))
        return dp(len(events)-1,k)
16 Smallest Sufficient TeamHard Bitmask DFS
In a project, you have a list of required skills
req_skills, and a list of people. The ith personpeople[i]contains a list of skills that the person has.Consider a sufficient team: a set of people such that for every required skill in
req_skills, there is at least one person in the team who has that skill. We can represent these teams by the index of each person.Return any sufficient team of the smallest possible size, represented by the index of each person. You may return the answer in any order. It is guaranteed an answer exists.
Constraints
people[i] are unique.people[i] is a skill in req_skills.A nice heavy-coding problem I would say. Most tricky in this month so far :).
The question’s model is set cover problem, which is NP complete, hence no exact polynomial-time solutions. Appropriate greedy algorithms can optimise the time complexity to approximately polynomial.
Indeed, we never no if we have achieved the minimal answer until searched all possible combinations. Therefore, the key is to constrain the possible combinations set:
skillsWhoskillsWho according to the descending orders of number of skills they have.Note that 4️⃣ and 5️⃣ do not cut every corner. They speed up the convergence by finding a smaller ans earlier. (essence of this greedy idea: we tend to desire people covering more skills)
class Solution:
    def smallestSufficientTeam(self, req_skills: List[str], people: List[List[str]]) -> List[int]:
        n = len(people)
        n_skills = len(req_skills)
        ans = [x for x in range(n)]
        for i, p in enumerate(people):
            people[i] = set(p)
        # discard useless
        for i, p1 in enumerate(people):
            for j, p2 in enumerate(people):
                if i==j: continue
                if p1.issubset(p2):
                    people[i] = set()
        # bitmask people skills
        people_masked = []
        for i in range(n):
            skillset = [(x in people[i]) for x in req_skills]
            sk = 0
            for i in skillset:
                sk = sk*2 + int(i)
            people_masked.append(sk)
        skillsWho = [[] for _ in range(n_skills)] 
        for p in range(n):
            for i in people[p]:
                skillsWho[req_skills.index(i)].append(p)
        for i in range(n_skills):
            skillsWho[i].sort(key=lambda x: -len(people[x]))
        
        def complete(now) -> int: 
            #-1 complete; otherwise first '0' loc
            skills = 0
            for x in now:
                skills = skills | people_masked[x]
            if skills == 2**n_skills-1:
                return -1
            else:
                bitmask = ""
                while skills>0:
                    bitmask = str(skills%2) + bitmask
                    skills = skills // 2
                bitmask = bitmask.zfill(n_skills)
                return bitmask.find("0")
        def dfs(now):
            nonlocal ans
            if len(now)>=len(ans): return
            nex = complete(now)
            print(now,nex)
            if nex==-1:
                ans = now
                return
            else:
                for p in skillsWho[nex]:
                    if p in now: continue
                    dfs(sorted(now+[p]))
        hardest = 0 # start search in the hardest skill
        for i in range(n_skills):
            if len(skillsWho[i])<len(skillsWho[hardest]): hardest = i
        for p1 in skillsWho[hardest]:
            dfs([p1])
        return(ans)
17 Add Two Numbers IIMedium Linked List
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Simple coding.
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        def toLinkedList(n: int) -> ListNode:
            l = None
            while n:
                val = n % 10
                n, l = n // 10, ListNode(val, l)
            return l if l else ListNode()
        def toInt(l: ListNode) -> int:
            n = 0
            while l:
                n=n*10+l.val
                l = l.next
            return n
        return toLinkedList(toInt(l1)+toInt(l2))
18 LRU CacheMedium Data Structure
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the
LRUCacheclass:
LRUCache(int capacity)Initialize the LRU cache with positive sizecapacity.
int get(int key)Return the value of thekeyif the key exists, otherwise return -1.
void put(int key, int value)Update the value of thekeyif thekeyexists. Otherwise, add the > key-value pair to the cache. If the number of keys exceeds thecapacityfrom this operation, evict the least recently used key.The functions
getandputmust each run inO(1)average time complexity.
Simple coding. Key to O(1) time complexity is
dict to store keysiter and next).class LRUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.elementDict = {}
    def get(self, key: int) -> int:
        if key in self.elementDict:
            val = self.elementDict.pop(key)
            self.elementDict[key] = val
            return val
        return -1        
    def put(self, key: int, value: int) -> None:
        if key in self.elementDict:
            self.elementDict.pop(key)
        else:
            if len(self.elementDict) == self.capacity:
                ancient = next(iter(self.elementDict))
                del self.elementDict[ancient]
        self.elementDict[key] = value
19 Non-overlapping IntervalsMedium Greedy
Given an array of intervals
intervalswhereintervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Greedy. We sort and start from the right, if the current fit in, then we take it, otherwise we drop it.
Fiddling with an example helps to get this idea quickly.
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals.sort(key=lambda x: x[0], reverse=True)
        current, drop = intervals[0], 0
        for s, e in intervals[1:]:
            if current[0]>=e:
                current = [s,e]
            else:
                drop+=1
        return(drop)
20 Asteroid CollisionMedium
We are given an array
asteroidsof integers representing asteroids in a row.For each asteroid, the absolute value represents its size, and the sign represents its direction (positive meaning right, negative meaning left). Each asteroid moves at the same speed.
Find out the state of the asteroids after all collisions. If two asteroids meet, the smaller one will explode. If both are the same size, both will explode. Two asteroids moving in the same direction will never meet.
Simple simulation. We use cur to record the current border. On the left of the border is the thing we have dealt with the collision.
Time Complexity should be below $O(n^2)$, because of potentially going to the end and going back.
class Solution:
    def asteroidCollision(self, asteroids: List[int]) -> List[int]:
        cur = 0
        for i in range(len(asteroids)):
            while cur and asteroids[cur-1]>0 and asteroids[i]<0 and abs(asteroids[cur-1])<abs(asteroids[i]):
                cur-=1#crush
            if asteroids[i]>0 or asteroids[cur-1]<0 or cur==0:
                asteroids[cur] = asteroids[i]
                cur+=1
            elif asteroids[cur-1] == abs(asteroids[i]):
                cur-=1
        return asteroids[:cur]
21 Number of Longest Increasing SubsequenceMedium DP
Given an integer array
nums, return the number of longest increasing subsequences.Notice that the sequence has to be strictly increasing.
Classic DP. $f[i]$ records the max length of increasing subsequence ending at $i$. Update count when finding previous length to be $f[i]-1$.
class Solution:
    def findNumberOfLIS(self, nums: List[int]) -> int:
        n = len(nums)
        f = count = [1]*n 
        for i in range(1,n):
            for j in range(i):
                if nums[i]<=nums[j]: continue
                if f[i] == f[j]+1:
                    count[i]+=count[j]
                elif f[i] < f[j]+1:
                    f[i], count[i] = f[j]+1, count[j]
        ans = max(f)
        return sum(count[i] for i in range(n) if f[i]==ans)
22 Knight Probability in ChessboardMedium
On an n x n chessboard, a knight starts at the cell
(row, column)and attempts to make exactlykmoves. The rows and columns are 0-indexed, so the top-left cell is(0, 0), and the bottom-right cell is(n-1, n-1).A chess knight has eight possible moves it can make, as illustrated below. Each move is two cells in a cardinal direction, then one cell in an orthogonal direction.
Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece would go off the chessboard) and moves there.
The knight continues moving until it has made exactly
kmoves or has moved off the chessboard.Return the probability that the knight remains on the board after it has stopped moving.
Simple coding. Just calculating probabilities step by step.
class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        probabilitys = [[0]*n for _ in range(n)]
        probabilitys[row][column] = 1
        jump = [(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)]
        MoveOffProb = 0
        for i in range(k):
            # calculate probability from previous round
            newProbabilitys = [[0]*n for _ in range(n)]
            for r, c in itertools.product(range(n),range(n)):
                for dr, dc in jump:
                    if 0<=r+dr<n and 0<=c+dc<n:
                        newProbabilitys[r+dr][c+dc] += probabilitys[r][c]/8
                    else:
                        MoveOffProb += probabilitys[r][c]/8
            probabilitys = newProbabilitys
        return(1-MoveOffProb)
23 All Possible Full Binary TreesMedium Recursion BinaryTree
Given an integer n, return a list of all possible full binary trees with
nnodes. Each node of each tree in the answer must haveNode.val == 0.Each element of the answer is the root node of one possible tree. You may return the final list of trees in any order.
A full binary tree is a binary tree where each node has exactly 0 or 2 children.
Nothing fancy, just list everything. We create a dictionary trees to store all full binary trees with number of node i. Then bottom-up.
# 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
class Solution:
    def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
        if not n%2: return []
        trees = defaultdict(list)
        trees[1].append(TreeNode(0))
        t3 = TreeNode(0)
        t3.left = TreeNode(0)
        t3.right = TreeNode(0)
        trees[3].append(t3)
        for i in range(5,n+1,2):
            l,r = 1, i-2
            while r>=1:
                for left_child in trees[l]:
                    for right_child in trees[r]:
                        tree = TreeNode(0)
                        tree.left, tree.right = left_child, right_child
                        trees[i].append(tree)
                r-=2
                l+=2
        return trees[n]
24 Pow(x,n)Easy DivideandConquer
Implement pow(x, n), which calculates
xraised to the powern(i.e., $x^n$).
Constraints
Simple coding, could top-down or bottom-up. Here we use cache() to cut corners.
class Solution:
    @lru_cache(None)
    def myPow(self, x: float, n: int) -> float:
        if not n: return 1
        elif n==1: return x
        elif n==-1: return 1/x
        return self.myPow(x, n//2) * self.myPow(x, n//2) * self.myPow(x, n%2)
25 Peak Index in a Mountain ArrayMedium BinarySearch
An array
arris a mountain if the following properties hold:
arr.length>= 3- There exists some i with
0 < i < arr.length - 1such that:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]Given a mountain array
arr, return the indexisuch thatarr[0] < arr[1] < ... < arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1].You must solve it in
O(log(arr.length))time complexity.
Nothing worth mentioning binary search.
class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        l,r = 0, len(arr)-1
        while True:
            mid = (l+r)//2
            if arr[mid]>arr[mid-1]:
                if arr[mid]>arr[mid+1]:
                    return mid
                else:
                    l=mid+1
            else:
                r = mid
26 Minium Speed to Arrive on TimeMedium BinarySearch
You are given a floating-point number hour, representing the amount of time you have to reach the office. To commute to the office, you must take n trains in sequential order. You are also given an integer array
distof lengthn, wheredist[i]describes the distance (in kilometers) of the ith train ride.Each train can only depart at an integer hour, so you may need to wait in between each train ride.
- For example, if the 1st train ride takes 1.5 hours, you must wait for an additional 0.5 hours before you can depart on the 2nd train ride at the 2 hour mark.
Return the minimum positive integer speed (in kilometers per hour) that all the trains must travel at for you to reach the office on time, or -1 if it is impossible to be on time.
Tests are generated such that the answer will not exceed $10^7$ and
hourwill have at most two digits after the decimal point.
Constraints
Then we find that, given a speed, we can quickly verify whether it can fulfill the task. So we binary search the possible speeds.
class Solution:
    def minSpeedOnTime(self, dist: List[int], hour: float) -> int:
        if hour+1 <= len(dist): return -1
        l, r = 1, max(dist)
        if hour%1!=0:
            r = max(r, dist[-1]//(hour-int(hour))+1)
        while l<r:
            mid = (l+r)//2
            need = sum(i//mid + (i%mid!=0) for i in dist[:-1]) + dist[-1]/mid
            if need<=hour:
                r=mid
            else:
                l = mid+1
        return int(l)
27 Maximum Running Time of N ComputersHard BinarySearch Greedy
You have n computers. You are given the integer
nand a 0-indexed integer array batteries where the ith battery can run a computer forbatteries[i]minutes. You are interested in running all n computers simultaneously using the given batteries.Initially, you can insert at most one battery into each computer. After that and at any integer time moment, you can remove a battery from a computer and insert another battery any number of times. The inserted battery can be a totally new battery or a battery from another computer. You may assume that the removing and inserting processes take no time.
Note that the batteries cannot be recharged.
Return the maximum number of minutes you can run all the
ncomputers simultaneously.
Hard to proceed at first. Then by a greedy idea, we discover it’s easy to check whether a life is viable (shown in the function check). Then we just binary search the life.
class Solution:
    def maxRunTime(self, n: int, batteries: List[int]) -> int:
        l = 1
        r = sum(batteries) // n
        def check(life: int) -> bool:
            return sum([min(x, life) for x in batteries])>=n*life
        while l<=r:
            mid = (l+r)//2
            if check(mid):
                l=mid+1
            else:
                r=mid-1
        return r
28 Predict the WinnerMedium DP Recursion
You are given an integer array nums. Two players are playing a game with this array: player 1 and player 2.
Player 1 and player 2 take turns, with player 1 starting first. Both players start the game with a score of 0. At each turn, the player takes one of the numbers from either end of the array (i.e.,
nums[0]ornums[nums.length - 1]) which reduces the size of the array by 1. The player adds the chosen number to their score. The game ends when there are no more elements in the array.Return true if Player 1 can win the game. If the scores of both players are equal, then player 1 is still the winner, and you should also return true. You may assume that both players are playing optimally.
总感觉以前哪里做过。。是HRT还是XTX的面试题吗😶
Simple DP. The idea is:
or).and). Then it’s clearly DP. Edge situation easy to handle. Again lru_cache to cut corners.class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        @lru_cache(None)
        def search(l: int,r: int,score1: int,score2: int, now1: bool) -> bool:
            nonlocal nums
            if l>r: return score1>=score2
            if now1:
                return search(l+1, r, score1+nums[l], score2, False) or search(l,r-1,score1+nums[r],score2,False)
            else:
                return search(l+1, r, score1, score2+nums[l], True) and search(l,r-1,score1,score2+nums[r],True)
        return search(0,len(nums)-1,0,0,True)
29 Soup ServingsMedium DP
ti mu tai chang le, bu xiang ban yun. just simple DP. Nothing to say.
class Solution:
    def soupServings(self, n: int) -> float:
        @lru_cache(None)
        def dfs(a,b):
            if a<=0 and b<=0:
                return 0.5
            elif a<=0:
                return 1
            elif b<=0:
                return 0
            return 0.25*(dfs(a-100,b)+dfs(a-75,b-25)+dfs(a-50,b-50)+dfs(a-25,b-75))
        if n>=4451:
            return 1
        else:
            return dfs(n,n)
30 Strange PrinterHard DP
There is a strange printer with the following two special properties:
- The printer can only print a sequence of the same character each time.
- At each turn, the printer can print new characters starting from and ending at any place and will cover the original existing characters.
Given a string
s, return the minimum number of turns the printer needed to print it.
DP is clear. How to proceed DP is hard. We consider **how many steps we take to change a string s from the form aaaaaa where a is s’s end, to s.
Key idea: there always exists an optimal strategy, where at each operation we use the printer to change the section of letters to its ending letter. i.e. change s[start:end+1] to s[end] * (end-start+1). Just argue by contradiction.
Then with this idea we can divide the problem into subproblems, thus proceeding DP.
I think the solution explains the idea very clearly.
class Solution:
    def strangePrinter(self, s: str) -> int:
        nextDiffIndex, prevDiffIndex = [-1] * len(s), [-1] * len(s)
        for i in range(len(s)-2, -1, -1):
            if s[i]!=s[i+1]:
                nextDiffIndex[i] = i+1
            else:
                nextDiffIndex[i] = nextDiffIndex[i+1]
        for i in range(1, len(s)):
            if s[i]!=s[i-1]:
                prevDiffIndex[i] = i-1
            else:
                prevDiffIndex[i] = prevDiffIndex[i-1]
        @lru_cache(None)
        def dp(start, end) -> int:
            #dp[l][r] = dp[j][i] + dp[i+1][r] + 1 for optimal i
            # we assume we already have s[end]
            if len(set(s[start:end+1])) == 1: return 0
            next = nextDiffIndex[start] if s[start]==s[end] else start
            if next == prevDiffIndex[end]: return 1
            return 1 + min([dp(next, nextend)+dp(nextend+1, end) for nextend in range(next, end)])
        return 1+dp(0, len(s)-1)        
Finished this problem at a Stabucks in Bilbao, with a broken leg. Apparently the Spanish add sugars to cold brew.
31 Minimum ASCII Delete Sum for Two StringsMedium DP
Given two strings
s1ands2, return the lowest ASCII sum of deleted characters to make two strings equal.
Constraints $1 \leq s1.length,\, s2.length \leq 1000$
A classic DP problem. Consider dp(i,j) to be the answer of s1[i:] and s2[j:].
class Solution:
    def minimumDeleteSum(self, s1: str, s2: str) -> int:
        @lru_cache(None)
        def dp(i, j) -> int:
            # ans since [i:] and [j:]
            nonlocal s1,s2
            if i==len(s1) and j==len(s2): return 0
            if i==len(s1) and j<len(s2):
                return sum([ord(x) for x in s2[j:]])
            if i<len(s1) and j==len(s2):
                return sum([ord(x) for x in s1[i:]])
            if s1[i]==s2[j]: return dp(i+1,j+1)
            return min(ord(s1[i])+dp(i+1,j), ord(s2[j])+dp(i,j+1))
        return dp(0,0)
Jul LeetCoding Challenge COMPLETED