leetcode刷题笔记-DP2

1751. Maximum Number of Events That Can Be Attended II

class Solution:
    def maxValue(self, events: List[List[int]], k: int) -> int:
        events.sort()
        self.memo = {}
        def help(i, events, k):
            if i >= len(events) or k == 0:
                return 0

            if (i, k) in self.memo:
                return self.memo[(i, k)]    
            start, end, value = events[i]
            # pick this event
            # j would be the index of the event which start time is > end
            j = bisect.bisect(events, [end+1, 0, 0])
            total1 = value + help(j, events, k-1)
            # or skip this event, find the next event > cur one
            j = bisect.bisect(events, [start, end, value])
            total2 = help(j, events, k)

            total = max(total1, total2)
            self.memo[(i, k)] = total
            return total
        
        return help(0, events, k)

        ''' if there is no limitation on K 
        events.sort()
        self.memo = {}
        def help(i, events):
            if i >= len(events):
                return 0

            if i in self.memo:
                return self.memo[i]    
            start, end, value = events[i]
            # pick this event
            # j would be the index of the event which start time is > end
            j = bisect.bisect(events, [end+1, 0, 0])
            total1 = value + help(j, events)
            # or skip this event, find the next event > cur one
            j = bisect.bisect(events, [start, end, value])
            total2 = help(j, events)

            total = max(total1, total2)
            self.memo[i] = total
            return total
        
        return help(0, events)
        '''

1691. Maximum Height by Stacking Cuboids

class Solution:
    def maxHeight(self, A: List[List[int]]) -> int:
        # The condition is width[i] <= width[j] and length[i] <= length[j] and height[i] <= height[j] 
        # Not just  width[i] <= width[j] and length[i] <= length[j]
        # if all 3 dimentions will smaller than another one, we use the longest one as the height
        A = sorted(map(sorted, A))
        A = [[0, 0, 0]] + A
        dp = [0] * len(A) # dp[j] = max(dp[i] + A[j][2])

        for j in range(1, len(A)):
            for i in range(j):
                if A[i][0] <= A[j][0] and A[i][1] <= A[j][1] and A[i][2] <= A[j][2]:
                    dp[j] = max(dp[j], dp[i] + A[j][2])
        
        return max(dp)

1162. As Far from Land as Possible

class Solution:
    def maxDistance(self, grid: List[List[int]]) -> int:
        # DP time/space: O(nm)/O(1)
        # loop from (top left) to (bottom right) and then reverse
        # cur cell is based on previous 2 cells on the top or left and 201 which is the max
        n, m = len(grid), len(grid[0])
        res = 0
        for i in range(n):
            for j in range(m):
                if grid[i][j] != 1:
                    # based on left grid or up grid
                    grid[i][j] = 201
                    if j > 0:
                        grid[i][j] = min(grid[i][j], grid[i][j-1]+1)
                    if i > 0:
                        grid[i][j] = min(grid[i][j], grid[i-1][j]+1)
  
        for i in range(n-1, -1, -1):
            for j in range(m-1, -1, -1):
                if grid[i][j] != 1:
                    if j < m-1:
                        grid[i][j] = min(grid[i][j], grid[i][j+1]+1)
                    if i < n - 1:
                        grid[i][j] = min(grid[i][j], grid[i+1][j]+1)
                    res = max(res, grid[i][j])
        
        return res - 1 if res != 201 else -1

2786. Visit Array Positions to Maximize Score

class Solution:
    def maxScore(self, nums: List[int], x: int) -> int:
        # dp, pick or skip
        # even odd means previous total till even num or odd num
        even = nums[0] if (nums[0] % 2 == 0) else -inf
        odd = nums[0] if (nums[0] % 2 != 0) else -inf
        curMax = max(even, odd) # total including cur num, but res does not necessarily need to have last one
        for i in range(1, len(nums)):
            nxt = nums[i]
            if nxt % 2 == 0:
                curMax = max(even, odd - x) + nxt 
                even = curMax
            else:
                curMax = max(odd, even - x) + nxt
                odd = curMax

        return max(odd, even)

1567. Maximum Length of Subarray With Positive Product

class Solution:
    def getMaxLen(self, nums: List[int]) -> int:
        re = 0
        neg = pos = 0

        for n in nums:
            if n == 0:
                neg = pos = 0
            elif n > 0:
                pos += 1
                neg = 0 if neg == 0 else neg + 1
            else:
                prneg = neg
                neg = pos + 1
                pos = 0 if prneg == 0 else prneg + 1
            # print(pos, neg)
            re = max(re, pos)
        return re

2466. Count Ways To Build Good Strings

class Solution:
    def countGoodStrings(self, low: int, high: int, zero: int, one: int) -> int:
        # dp  https://leetcode.com/problems/count-ways-to-build-good-strings/solutions/2807155/coin-change-problem-variant/?orderBy=most_votes
        # Given we can append 0 zero number of times and 1 one number of times
        # so if zero is 4 then 0000 is considered one string and one is 3 then 111 is considered one string
        # now using these two strings we will have to make some new string that has a length between low and high inclusive
        # Now treat the length of final string to make as a target that needs to be achieved
        # and the length of strings from which the final string to be made as coin values

        # bottom up: dp[length] = dp[length-one] + dp[lenght-zero]

        dp = [0] * (high+1)
        dp[0] = 1  # base
        re = 0
        for i in range(1, high+1):
            if i >= zero:
                dp[i] = dp[i-zero]
            if i >= one:
                dp[i] += dp[i-one]

            if low <= i <= high:
                re += dp[i]
                re %= 10**9 + 7
        return re

198. House Robber

class Solution:
    def rob(self, nums: List[int]) -> int:
        # dp[i] = max(dp[i-1], dp[i-2] + nums[i]), better example [2, 1, 1, 2]
        if len(nums) <= 2:
            return max(nums)
        
        pre1, pre2 = max(nums[1], nums[0]), nums[0]  # dp[i-1], dp[i-2]
        re = 0
        for n in nums[2:]:
            # print(n, pre1, pre2)
            re = max(pre1, pre2 + n)
            # print(re)
            pre1, pre2 = re, pre1
        return re

152. Maximum Product Subarray

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        # 存 最大product 和最小Product [-1, -2, -9, -6]
        re = curMax = curMin = nums[0]
        
        for n in nums[1:]:
            curMax *= n
            curMin *= n
            # print("n", n)
            # print("before", curMax, curMin)
            curMax, curMin = max(n, max(curMax, curMin)), min(n, min(curMax, curMin))
            # print("update", curMax, curMin)
            re = max(curMax, re)
            # print("re", re)
        return re

790. Domino and Tromino Tiling

class Solution:
    def numTilings(self, n: int) -> int:
        # https://leetcode.com/problems/domino-and-tromino-tiling/solutions/1620975/c-python-simple-solution-w-images-explanation-optimization-from-brute-force-to-dp/
        '''
        dp[i][previousGap] denotes the number of ways to tile a grid starting from the ith column and previousGap denotes whether previous column had gap in it or not. 
        Time Complexity : O(N) where N is the given number of columns of grid
        Space Complexity : O(N), required for recursive stack and maintaining dp
  
        @cache
        def dp(i, pre_gap):  # start to pave i column, need to pave i from 0 to n-1
            if i > n:
                return 0
            if i == n:
                return not pre_gap
            if pre_gap:
                return dp(i+1, False) + dp(i+1, True)
            else:
                return dp(i+1, False) + dp(i+2, False) + 2 * dp(i+2, True) 
        return dp(0, False) % 1_000_000_007
        '''

        '''
        use a dp array where dp[i][0] denotes the number of ways to tile the grid till ith column (including ith column) and keeping no gap & dp[i][1] denotes the number of ways to completely tile the grid till ith column keeping a gap in i+1th column (a square protruding out).
        
        dp = [[0, 0] for _ in range(n+2)]
        dp[1], dp[2] = [1, 1], [2, 2]  # dp[1, 1] 得是1 不能是2, 后面的dp[i-2][1] 才能乘以2
        for i in range(3, n+1):
            dp[i][0] = dp[i-1][0] + dp[i-2][0] + 2*dp[i-2][1]
            dp[i][1] = dp[i-1][0] + dp[i-1][1]
        return dp[n][0] % 1_000_000_007
        '''
        # 上面只用了dp[i], dp[i-1], dp[i-2], 所以只需要3个空间
        dp = [[0, 0] for _ in range(3)]
        dp[1], dp[2] = [1, 1], [2, 2]
        for i in range(3, n+1):
            dp[i%3][0] = dp[(i-1)%3][0] + dp[(i-2)%3][0] + 2*dp[(i-2)%3][1]
            dp[i%3][1] = dp[(i-1)%3][0] + dp[(i-1)%3][1]
        return dp[n%3][0] % 1_000_000_007

2311. Longest Binary Subsequence Less Than or Equal to K

class Solution:
    def longestSubsequence(self, s: str, k: int) -> int:
        '''
        dp[i] means the minimum value of the subsequence with length i
        Time O(n^2)
        Space O(n)
        
        dp = [0]
        for v in map(int, s):  # 从头往后拿s的字母,并转为Int
            if dp[-1] * 2 + v <= k:  # 拿后面的数字,前面的进一位
                dp.append(dp[-1] * 2 + v)
            for i in range(len(dp) - 1, 0, -1):
                dp[i] = min(dp[i], dp[i - 1] * 2 + v)  #  不要i的那位,换成当前这个位置的数,即v
        return len(dp) - 1
        ''' 

        '''
        Greedy
        拿所有的0, 然后尽量的从右边拿1
        Time O(n)
        Space O(1)
        '''

        re = 0
        n = len(s)
        bit = 1  # 这一位如果是1代表的值

        for v in map(int, s[::-1]):  # 为了尽量从右边拿1, 这些1和0构成的数要小于k
            if (v == 0 or bit <= k):
                k -= bit * (v - 0)
                re += 1
            bit = bit << 1
        return re

1105. Filling Bookcase Shelves

class Solution:
    def minHeightShelves(self, books: List[List[int]], shelfWidth: int) -> int:
        n = len(books)
        dp = [float('inf') for _ in range(n+1)] # dp[i]: height for books 0 to i - 1
        dp[0] = 0 # no book height
        for i in range(1, n+1):
            w = shelfWidth
            h = 0
            j = i - 1 # j is the index of the book
            while j >= 0 and w - books[j][0] >= 0:  # 拿前面的书来组成新的一层
                w -= books[j][0]
                h = max(h, books[j][1])  # 这一层最大的高度
                dp[i] = min(dp[i], dp[j] + h) # dp[j] is the book from 0 to j-1
                j -= 1
        return dp[-1]

1653. Minimum Deletions to Make String Balanced

class Solution:
    def minimumDeletions(self, s: str) -> int:
        # s[i] = b dp[i] = dp[i-1]
        # s[i] = a dp[i] = min: count b (remove all the previous b) or dp[i-1] + 1 remove this a
        
        dp = [0 for _ in range(len(s) + 1)]
        cntB = 0
        for i, c in enumerate(s, 1):
            if c == 'b':
                dp[i] = dp[i-1]
                cntB += 1
            else:
                dp[i] = min(dp[i-1]+1, cntB)
        return dp[-1]

926. Flip String to Monotone Increasing

class Solution:
    def minFlipsMonoIncr(self, s: str) -> int:
        dp = [0 for _ in range(len(s) + 1)]  # best re when s with len only to i
        # when s[i] = 1 dp[i] = dp[i-1] when the last digit is 1, you don't need to flip for this digit
        # when s[i] = 0, dp[i] = min dp[i-1] + 1 (flip last one) or count_1  (flip all previous 1)
        
        cnt1 = 0
        for i, c in enumerate(s, 1):
            if c == '1':
                dp[i] = dp[i-1]
                cnt1 += 1
            else:
                dp[i] = min(dp[i-1] + 1, cnt1)
        return dp[-1]
        
                
                

418. Sentence Screen Fitting

class Solution:
    def wordsTyping(self, sentence: List[str], rows: int, cols: int) -> int:
        '''
        1. Based on the above observation, in the first for loop we compute the number of words that can be placed in the row if ith word is used as the starting word. This is saved as dp[i]. Note that this value can be greater than n.
        
        2.In the next for loop we calculate how many words are placed in each row based on dp[i]. Imagine placing the 0th word in the row-0, then this row will hold dp[0] words. Next, which word will be placed on the start of next row? We calculate that using dp[k] % n (Remember dp[i] can be greater than n).
        '''
        n = len(sentence)
        dp = [0 for _ in range(n)]  # the number of workds can be fit in 1 line if start with word i
        
        for i in range(n):  # loop i to calcuate the dp[i] which starts with word i
            cur_total_length = 0
            number_of_words = 0
            cur_index = i
            while (cur_total_length + len(sentence[cur_index % n]) <= cols):
                cur_total_length += len(sentence[cur_index % n])
                cur_total_length += 1  # space  
                cur_index += 1
                number_of_words += 1
            dp[i] = number_of_words
        
        # calcualte how many words can be fit into all rows
        count = 0
        index = 0
        for r in range(rows):
            count += dp[index]
            index = (dp[index] + index) % n
            
        return count // n
            
                

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值