zoukankan      html  css  js  c++  java
  • leetcode解题笔记--part1--dynamic programming


     5. Longest Palindromic Substring  ❤

     62. Unique Paths

     63. Unique Paths II  ❤

     64. Minimum Path Sum

     91. Decode Ways

     95. Unique Binary Search Trees II  ❤❤

     96. Unique Binary Search Trees    ❤❤

     120. Triangle

     139. Word Break   ❤❤

     152. Maximum Product Subarray  ❤❤

     213. House Robber II

     221. Maximal Square  ❤

     264. Ugly Number II    ❤❤

     279. Perfect Squares    ❤❤

     300. Longest Increasing Subsequence  ❤

     304. Range Sum Query 2D - Immutable  

     309. Best Time to Buy and Sell Stock with Cooldown  ❤❤



    5. Longest Palindromic Substring 【Medium】  返回目录


     题目:

    解体思路:

    dp[i][j] = dp[i+1][j-1] & s[i+1]==s[j-1]

    时间复杂度O(n^2)

    code:  AC  但是时间很长

     1 def longestPalindrome(self, s):
     2         """
     3         :type s: str
     4         :rtype: str
     5         """
     6         if not s:
     7             return ""
     8         length = len(s)
     9         max_length = 1
    10         result = s[0]
    11         dp = [[0 for j in range(length)] for i in range(length)]
    12         for i in range(length):
    13             dp[i][i] = 1
    14             if i > 0:
    15                 dp[i][i-1] = 1
    16         for i in range(length-2,-1,-1):
    17             for j in range(i+1,length):
    18                 if dp[i+1][j-1] and s[i]==s[j]:
    19                     dp[i][j] = 1
    20                     if j-i+1 > max_length:
    21                         max_length = j-i+1
    22                         result = s[i:j+1]
    23         return result

    看来下答案,有个线性时间的算法,Manacher马拉车算法,就是专门解决找字符串中最长回文子串

    https://www.cnblogs.com/grandyang/p/4475985.html

    code:

     1 def longestPalindrome(self, s):
     2         """
     3         :type s: str
     4         :rtype: str
     5         """
     6         T = '#'.join('^{}$'.format(s))
     7         n = len(T)
     8         p = [1] * n
     9         mx = 0
    10         center = 0
    11         for i in range(1,n-1):
    12             p[i] = min(p[2*center-i], mx-i) if mx > i else 1
    13             while T[i+p[i]] == T[i-p[i]]:
    14                 p[i] += 1
    15             if i + p[i] > mx:
    16                 center,mx = i, i+p[i]
    17         maxLen, centerIndex = max((n,i) for i,n in enumerate(p))
    18         return s[(centerIndex-maxLen)//2:(centerIndex+maxLen)//2-1]


    91. Decode Ways 【Medium】  返回目录


    题目:

     解题思路:

    先写出编码当前位置时,与之前结果的递推关系,再考虑各种情况,具体思路见代码

     1 def numDecodings(self, s):
     2         """
     3         :type s: str
     4         :rtype: int
     5         """
     6         if not s or s[0]=='0':
     7             return 0
     8         res1_cur, res1_pre, res1_prepre = 1,1,1
     9         res2_cur, res2_pre, res2_prepre = 0,0,0
    10         for i in range(1,len(s)):
    11             if s[i]=='0':
    12                 res1_cur = 0
    13                 if 10<=int(s[i-1:i+1])<=26:
    14                     res2_cur = res1_prepre+res2_prepre
    15                 else:
    16                     return 0
    17             else:
    18                 res1_cur = res1_pre+res2_pre
    19                 if 10<=int(s[i-1:i+1])<=26:
    20                     res2_cur = res1_prepre+res2_prepre
    21                 else:
    22                     res2_cur = 0
    23             res1_pre,res1_prepre = res1_cur,res1_pre
    24             res2_pre,res2_prepre = res2_cur,res2_pre
    25         return res1_cur+res2_cur


    95. Unique Binary Search Trees II 【Medium】  返回目录


     题目:

     解题思路:

    注意这题是二叉树,所以节点左边的树节点都小于根节点,节点右边的树节点都大于根节点

     参考的别人的答案,用的迭代方法:

     1 # Definition for a binary tree node.
     2 # class TreeNode(object):
     3 #     def __init__(self, x):
     4 #         self.val = x
     5 #         self.left = None
     6 #         self.right = None
     7 
     8 class Solution(object):
     9     def generate(self,start,end):
    10         trees = []
    11         for root in range(start,end+1):
    12             for left in self.generate(start,root-1):
    13                 for right in self.generate(root+1,end):  
    14                     node = TreeNode(root)
    15                     node.left = left
    16                     node.right = right
    17                     trees.append(node)
    18         return trees or [None]
    19     def generateTrees(self, n):
    20         """
    21         :type n: int
    22         :rtype: List[TreeNode]
    23         """
    24         if n<1:
    25             return []
    26         return self.generate(1,n)
    27         

    迭代方法相较于动态规划来说,更加耗时耗空间,因为会重复很多冗余的步骤

    但是这道题写动态规划的话会有点繁琐


    96. Unique Binary Search Trees 【Medium】    返回目录


     题目:

    解题思路:   同上题,而且比上题简单很多

    见代码: 使用迭代超时了

     1 def generate(self,start,end):
     2         if start==end+1:
     3             return 1
     4         res = 0
     5         for root in range(start,end+1):
     6             res += self.generate(start,root-1) * self.generate(root+1,end)
     7         return res
     8     def numTrees(self, n):
     9         """
    10         :type n: int
    11         :rtype: int
    12         """
    13         return self.generate(1,n)
    14         
    15         

    改成动态规划做法:

    code:

     1 class Solution(object):
     2     def numTrees(self, n):
     3         """
     4         :type n: int
     5         :rtype: int
     6         """
     7         res = [[1 for i in range(n+2)] for j in range(n+2)]
     8         for k in range(2,n+1):
     9             for i in range(1,n-k+2):
    10                 j = i + k-1
    11                 res[i][j] = 0
    12                 for m in range(j-i+1):
    13                     res[i][j] += res[i][i-1+m] * res[m+i+1][j]                
    14         return res[1][n]

    看了下参考答案,发现我的要复杂好多,我想要填充一个二维数组,而且还挺恶心的,斜对角线填充,大神的答案只需要填充一个一维数组就可以了

    G(n) 表示 (1,n)的二叉树个数     F(i,n)表示以i为根结点range为(1,n)的二叉树个数

    这里不用管不同的数字,只要结点数确定的不同二叉树的组成方法就行

     1 def numTrees(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         res = [1 if i<2 else 0 for i in range(n+1) ]
     7         for i in range(2,n+1):
     8             for j in range(i):
     9                 res[i] += res[j] * res[i-j-1]
    10         return res[n]

     


    139. Word Break 【Medium】  返回目录


     题目:

     解题思路:

    这道题我没什么思路,就直接看了答案,直接看代码吧

     1 def wordBreak(self, s, wordDict):
     2         """
     3         :type s: str
     4         :type wordDict: List[str]
     5         :rtype: bool
     6         """
     7         dp = [0 if i>0 else 1 for i in range(len(s)+1)]
     8         for i in range(len(s)+1):
     9             for j in range(i):
    10                 if s[j:i] in wordDict and dp[j]:
    11                     dp[i] = 1
    12         return dp[len(s)]==1       

    这样的题就是要看怎么划分步骤,一步一步的确定当前位置是否正确,模拟人的一个策略从而找出动态规划方程

     


    213. House Robber II 【Medium】  返回目录


     题目:

     先做非环形的情况,dp[i] = max(dp[i-1],dp[i-2]+nums[i])     max(不偷当前,偷当前)

     1 def rob(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if n<2: return sum(nums)
     8         dp = [nums[0] if i<1 else 0 for i in range(n)]
     9         dp[1] = max(nums[0],nums[1])
    10         for i in range(2,n):
    11             dp[i] = max(dp[i-1],dp[i-2]+nums[i])
    12         return dp[n-1]

    这种情况是可以节省空间的 O(n)-> O(1)

     1 def rob(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if n<2: return sum(nums)
     8         prepre = nums[0]
     9         pre = max(nums[0],nums[1])
    10         cur = pre
    11         for i in range(2,n):
    12             cur = max(pre,prepre+nums[i])
    13             pre,prepre = cur,pre
    14         return cur

    对于环形,只需要断开一头就变成了链状,这里假设不偷第i家,那么i-1和i+1都不会有限制关系,所以这里两种情况,不偷连续两家取结果最大值,为了方便计算,这里取0和n-1

    1  def circle_rob(self, nums):
    2         n = len(nums)
    3         if n == 1:
    4             return nums[0]
    5         return max(rob(nums[0:n-1]),rob(nums[1:n]))


    221. Maximal Square 【Medium】  返回目录


     题目:

    解题思路:

    if matrix[i][j] = 0:  dp[i][j] = 0

    else:  dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1    O(mn) space  O(mn) time

    进行优化,只是依赖于前面三个变量,所以只需要一列   O(mn) time  O(min(m,n)) space

    O(mn) space 的代码很好实现

     1 def maximalSquare(self, matrix):
     2         """
     3         :type matrix: List[List[str]]
     4         :rtype: int
     5         """
     6         m = len(matrix)
     7         if not m:
     8             return 0
     9         n = len(matrix[0])
    10         res = 0
    11         dp = [[int(matrix[i][j]) for j in range(n)] for i in range(m)]
    12         for l in dp:
    13             if sum(l) > 0:
    14                 res = 1
    15         for i in range(1,m):
    16             for j in range(1,n):
    17                 if matrix[i][j] == '1': 
    18                     dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1
    19                     if res < dp[i][j]:
    20                         res = dp[i][j]
    21         return res**2

    优化代码,只保留两列

     1 def maximalSquare(self, matrix):
     2         """
     3         :type matrix: List[List[str]]
     4         :rtype: int
     5         """
     6         m = len(matrix)
     7         if not m:
     8             return 0
     9         n = len(matrix[0])
    10         pre = [int(matrix[i][0]) for i in range(m)]
    11         res = max(pre)
    12         cur = [0 for i in range(m)]
    13         for j in range(1,n):
    14             cur[0] = int(matrix[0][j])
    15             res = max(res,cur[0])
    16             for i in range(1,m):
    17                 if matrix[i][j] == '1':
    18                     cur[i] = min(cur[i-1],min(pre[i-1],pre[i])) + 1
    19                     res = max(res,cur[i])   
    20                 else:
    21                     cur[i] = 0
    22             cur,pre = pre,cur
    23             print(cur,pre)
    24         return res**2

    优化后的代码如下:只保留一列

     1 def maximalSquare(self, matrix):
     2         """
     3         :type matrix: List[List[str]]
     4         :rtype: int
     5         """
     6         m = len(matrix)
     7         if not m:
     8             return 0
     9         n = len(matrix[0])
    10         dp = [0 for i in range(m+1)]
    11         res = 0
    12         pre = 0
    13         
    14         for j in range(n):
    15             for i in range(1,m+1):
    16                 temp = dp[i]     #保存之前的dp[i]的结果
    17                 if matrix[i-1][j] == '1':
    18                     dp[i] = min(dp[i],min(dp[i-1],pre)) + 1    dp[i]就是pre[i],  dp[i-1]已经是新计算过的也就是cur[i-1]
    19                     res = max(res,dp[i])
    20                 else:
    21                     dp[i] = 0
    22                 pre = temp      #pre[i-1]
    23         return res**2


    264. Ugly Number II 【Medium】    返回目录


     题目:

    解题思路:

    1, 2, 3,   4, 5,   6,      8,     9,   10, 12

    1, 2, 3, 2x2,  5, 2x3, 4x2, 3x3, 2x5, 6x2 

    有点难,直接看答案了

    k[1] = min(k[0]x2, k[0]x3, k[0]x5)   取的是k[0]x2,所以我们把2的指针移向k[0]->k[1]

    k[2] = min(k[1]x2, k[0]x3, k[0]x5)   对于6这种情况,要同时移动指针2和指针3

     1 def nthUglyNumber(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         if n<0: return False
     7         if n == 1:
     8             return 1
     9         t2 = t3 = t5 = 0
    10         dp = [1 if i<1 else 0 for i in range(n)]
    11         for i in range(1,n):
    12             dp[i] = min(dp[t2]*2, min(dp[t3]*3, dp[t5]*5))
    13             if dp[i] == dp[t2]*2: t2 += 1
    14             if dp[i] == dp[t3]*3: t3 += 1
    15             if dp[i] == dp[t5]*5: t5 += 1
    16         return dp[n-1]
    17         


    279. Perfect Squares 【Medium】  返回目录


    题目:

    for i in range(n):

    dp[n] = min(dp[n], dp[i]+dp[n-i])

    边界条件:

    dp[0] = 0

    dp[1] = 1

    这个算法超时了 :  O(n^2)

     1 def numSquares(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         dp = [1 if i==1 else 0 for i in range(n+1)]
     7         for i in range(2,n+1):
     8             res = i**0.5
     9             if res.is_integer():
    10                     dp[i] = 1
    11             else:
    12                 for k in range(1,i//2+1):
    13                     if not dp[i]:
    14                         dp[i] = dp[k]+dp[i-k]
    15                     else:
    16                         dp[i] = min(dp[i],dp[k]+dp[i-k])
    17         return dp[n]

     知道我败在了哪里吗?败在第二个循环上,直接+1循环真的很笨啊,具体见代码:

    (For each i, it must be the sum of some number (i-j*j)) and a perfect square number j*j)

    还是超时了,python有毒

     1 import sys
     2 class Solution:
     3     def numSquares(self, n):
     4         """
     5         :type n: int
     6         :rtype: int
     7         """
     8         dp = [sys.maxsize for i in range(n+1)]
     9         dp[0] = 0
    10         for i in range(1,n+1):
    11             j = 1
    12             while j*j <= i:
    13                 dp[i] = min(dp[i],dp[i-j*j]+1)
    14                 j += 1
    15         return dp[n]

     看了一个答案,唯一的可以pass不超时的python代码:

     1 class Solution:
     2     _dp = [0]    类的公共属性,建立不同的对象的时候可以进行复用,这是针对测试样例是从1递增的,所以在计算567的时候可以复用566的答案
     3     def numSquares(self, n):
     4         """
     5         :type n: int
     6         :rtype: int
     7         """
     8         dp = self._dp
     9         while len(dp) <= n:
    10             dp += min(dp[-i*i] for i in range(1,int(len(dp)**0.5+1))) + 1,
    11         return dp[n]


    300. Longest Increasing Subsequence 【Medium】   返回目录


     题目:

    for j in range(i):    if nums[j]<nums[i]:   dp[i] = max(dp[i],dp[j]+1)

    O(n^2)

     1 def lengthOfLIS(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if not n: return 0
     8         dp = [1 for i in range(n)]
     9         for i in range(1,n):
    10             for j in range(i):
    11                 if nums[j] < nums[i]:
    12                     dp[i] = max(dp[i],dp[j]+1)
    13         return max(dp)

     O(nlogn)

     1 def lengthOfLIS(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         tails = [0] * len(nums)
     7         size = 0
     8         for x in nums:
     9             i, j = 0, size
    10             while i != j:
    11                 m = (i + j) // 2
    12                 if tails[m] < x:
    13                     i = m + 1
    14                 else:
    15                     j = m
    16             tails[i] = x
    17             size = max(i + 1, size)
    18         return size

    tail[i]记录的是长度为i+1的上升子序列的最小尾部    size是当前的最大长度  因为tail可能是升序的,所以可以使用二分查找进行更新


    304. Range Sum Query 2D - Immutable 【Medium】     返回目录


     题目:

    说是对象初始化一次,但是会连续call很多次sumRegion,所以我们不能直接循环做加法,会超时,所以要事先算好总和,用对角点做减法

     1 class NumMatrix:
     2     def __init__(self, matrix):
     3         """
     4         :type matrix: List[List[int]]
     5         """
     6         if matrix is None or not matrix:
     7             return 
     8         n,m = len(matrix),len(matrix[0])
     9         self.sums = [[0 for j in range(m+1)] for i in range(n+1)]
    10         for i in range(1,n+1):
    11             for j in range(1,m+1):
    12                 self.sums[i][j] = matrix[i-1][j-1] + self.sums[i][j-1] + self.sums[i-1][j] - self.sums[i-1][j-1]
    13 
    14     def sumRegion(self, row1, col1, row2, col2):
    15         """
    16         :type row1: int
    17         :type col1: int
    18         :type row2: int
    19         :type col2: int
    20         :rtype: int
    21         """
    22         row1, col1, row2, col2 = row1+1, col1+1, row2+1,col2+1
    23         return self.sums[row2][col2] - self.sums[row2][col1-1] - self.sums[row1-1][col2] + self.sums[row1-1][col1-1]
    24 
    25 
    26 # Your NumMatrix object will be instantiated and called as such:
    27 # obj = NumMatrix(matrix)
    28 # param_1 = obj.sumRegion(row1,col1,row2,col2)

     


    309. Best Time to Buy and Sell Stock with Cooldown 【Medium】   返回目录


     题目:

    解题思路:

    动态规划主要是要能找到相应的状态,以及状态之间的转移方程,有点类似于状态机

    这里主要有三个状态,如下图(复制的别人的解法)

    s0: rest[i] = max(sell[i-1], buy[i-1], rest[i-1])    为了表示buy[i]<=rest[i],还加上了sell[i-1],所以不会出现[buy, rest, buy]的情况  毫无意义,可以删除,因为rest[i]=sell[i-1]

    s1:  buy[i] = max(rest[i-1]-price, buy[i-1])

    s2: sell[i] = max(buy[i-1]+price, sell[i-1])

    又因为 rest[i] = sell[i-1]

    进行替换变成:

    buy[i] = max(sell[i-2]-price, buy[i-1])

    sell[i] = max(buy[i-1]+price, sell[i-1])

    继续优化,把O(n)space 改成 O(1) space

     1 def maxProfit(self, prices):
     2         """
     3         :type prices: List[int]
     4         :rtype: int
     5         """
     6         if len(prices) < 2:
     7             return 0
     8         sell, buy, prev_sell, prev_buy = 0, -prices[0], 0, 0
     9         for price in prices:
    10             prev_buy = buy
    11             buy = max(prev_sell - price, prev_buy)
    12             prev_sell = sell
    13             sell = max(prev_buy + price, prev_sell)
    14         return sell

     

     

    322. Coin Change 【Medium】   返回目录


     题目:

     不是特别难,

    for i in range(amount):

      for j in coins:

        dp[i] = min(dp[i], 1+dp[i-j])

    代码如下: 超时了  过了样例 172/182

     1 def coinChange(self, coins, amount):
     2         """
     3         :type coins: List[int]
     4         :type amount: int
     5         :rtype: int
     6         """
     7         if not amount:
     8             return 0
     9         dp = [1 if i+1 in coins else -1 for i in range(amount)]
    10         for i in range(amount):
    11             if dp[i]!=1:
    12                 for j in coins:
    13                     if j<=i+1 and dp[i-j]!=-1:
    14                         if dp[i]==-1:
    15                             dp[i] = 1 + dp[i-j]
    16                         else:
    17                             dp[i] = min(dp[i], 1+dp[i-j])
    18         return dp[amount-1]

     看了下答案,感觉和我的算法很像啊

    def coinChange(self, coins, amount):
            """
            :type coins: List[int]
            :type amount: int
            :rtype: int
            """
            dp = [amount+1 for i in range(amount+1)]
            dp[0] = 0
            for i in range(amount+1):
                for j in coins:
                    if j <= i:
                        dp[i] = min(dp[i], dp[i-j]+1)
            return -1 if dp[amount] > amount else dp[amount]

     我真笨,不知道怎么处理这个-1,加了很多判断语句,所以才会超时。  而且把1也一块融合到里面了,代码简洁了很多

      


    338. Counting Bits  【Medium】   返回目录


     题目:

     这个题,开始我只能想到说如果是奇数,那么它必然只是比前一个偶数多1, 对于进位的情况想不清楚,然后就直接看答案,是属于位操作

    比较巧妙的就是发现每个数与它右移1位的数字只有最后一位不同

    dp[i] = dp[i>>1] + (i & 1)   注意i & 1要加括号,因为  +  比 &的优先级更高

    1 def countBits(self, num):
    2         """
    3         :type num: int
    4         :rtype: List[int]
    5         """
    6         dp = [0 for i in range(num+1)]
    7         for i in range(1,num+1):
    8             dp[i] = dp[i>>1] + (i & 1)
    9         return dp


    343. Integer Break 【Medium】    返回目录


     题目:

     解题思路:

    这道题,挺好想的,和为n  假设分成两个数字,j和i-j那么 dp[i] = max(dp[i], dp[j]*dp[i-j])

    初始情况就是dp[1] = 1, 但是发现忘记对数字它本身是否要继续分进行讨论,2如果要继续分的话只能是1*1 但是它本身就是2,  所以改为

    dp[i] = max(dp[i], max(j,dp[j])*max(dp[i-j],i-j))     我写代码的时候愚蠢了一下  写成了 dp[i] = max(dp[i],max(dp[j]*dp[i-j],  j*(i-j)))这就是很蠢了

     1 def integerBreak(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         dp = [1 if i==1 else 0 for i in range(n+1)]
     7         for i in range(2,n+1):
     8             for j in range(1,i//2+1):
     9                 dp[i] = max(dp[i], max(dp[j],j)*max(dp[i-j],(i-j)))
    10         return dp[n]

    这个解法 O(n^2) time  O(n) space

    看参考答案发现有数学的解法  O(n) time  O(1) space

    f = x(N-x)  什么时候取最大  中值的时候,所以 当N是偶数时 (N/2)*(N/2)  当N为奇数时   (N-1)/2 * (N+1)/2

    当划分后的乘积大于 N本身时,才需要进行划分

    (N/2) * (N/2) >= N,  N>= 4

    (N-1)/2 * (N+1)/2 >= N ,  N>= 5

    以上式子说明 factors必然是 小于4的  因为大于等于4就是可分的, 所以就是 1, 2, 3,   1不用考虑,那就只剩下2和3了,那就尽可能的使用3  因为 3*3 >2*2*2 所以说最优的乘积中最好不要多于3个2

    代码如下:

     1 def integerBreak(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         if n==2:
     7             return 1
     8         if n==3:
     9             return 2
    10         res = 1
    11         while n> 4:
    12             res *= 3
    13             n -= 3
    14         res *= n
    15         return res


    351. Android Unlock Patterns 【Medium】   返回目录   【Locked】


     题目:   Google 面试题

     虽然是分在dp标签下的,但是看答案大多是用的dfs+回溯

    我们可以发现 1, 3 ,7, 9是对称的,所以只需要以其中一个作为开始点,结果乘以4

    2, 4,  6, 8也是对称的, 5单独一个

    有个限制条件就是访问两个数字之间的数字必须要访问过,所以用mid数组记录两个数字之间的数字是什么 

    dfs(m,n,len,num)  指当前长度为len, 初始访问结点是num, 长度在m,n之间的解锁方式个数

    代码如下:

     1 class Solution(object):
     2     def dfs(self, m, n, len, num):
     3         res = 0
     4         if len >= m: 
     5             res += 1
     6         len += 1
     7         if len > n:
     8             return res
     9         visited[num] = True
    10         for i in range(1,10):
    11             if not visited[i] and visited[mid[num][i]]
    12             res += self.dfs(m,n,len,i)
    13         visited[num] = False
    14         return res
    15 
    16     def numberOfPatterns(self, m, n):
    17         """
    18         :type m,n: int
    19         :rtype: int
    20         """
    21         visited = [False for i in range(10)]
    22         visited[0] = True
    23         mid = [[0 for j in range(10)] for i in range(10)]
    24         mid[1][3] = mid[3][1] = 2
    25         mid[1][7] = mid[7][1] = 4
    26         mid[3][9] = mid[9][3] = 6
    27         mid[7][9] = mid[9][7] = 8
    28         mid[2][8] = mid[8][2] = mid[4][6] = mid[6][4] = 5
    29         mid[1][9] = mid[9][1] = mid[3][7] = mid[7][3] = 5
    30         return self.dfs(m,n,1,1)*4 + dfs(m,n,1,2)*4 + dfs(m,n,1,5)

    我感觉我对dfs的回溯还是不太清楚,好好理清一下,这里主要是算的以num为end的path的个数加和。


    357. Count Numbers with Unique Digits 【Medium】   返回目录


     题目:

    这就是一个简单的数学问题,要找到n位数中由不同数字组成的数的总个数

    dp[1]  0<=x<10   dp[1]=10

    dp[2]  第一位数不能是0  所以是 9*9   就是一个全排列问题

    dp[3] = 9*9*8

    dp[>=11]  = 0

    code:  O(1) time   O(1) space

     1 def countNumbersWithUniqueDigits(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         if not n:
     7             return 1
     8         count = 10
     9         res = 9
    10         remains = 9
    11         while n>1 and remains> 0:
    12             n -= 1
    13             res *= remains
    14             count += res
    15             remains -= 1
    16         return count
    17         


    361. Bomb Enemy 【Medium】 【Locked】  返回目录


     题目:

     感觉locked题目都好难啊,我只想到了最笨的暴力方法,O(m*n)  用空间换时间

    用数组记录每个位置的行炸死个数,另一个数组记录每个位置的每列炸死个数,这样O(m+n) space  也就是O(max(m,n)) space  最后再遍历一遍求最大,所以O(m*n) time

    进行优化就是对于先遍历行,只需要用一个位置来记录行,所以O(min(m,n)) space, O(m*n) time

     1 def maxKilledEnemies(self, grid):
     2         m = len(grid)
     3         if not m:
     4             return 0
     5         n = len(grid[0])
     6         rowhits = 0 
     7         colhits = [0 for i in range(n)]
     8         res = 0
     9         for i in range(m):
    10             for j in range(n):
    11                 if not i or grid[i-1][j] == 'W':
    12                     colhits[j] = 0
    13                     for k in range(i,m): 
    14                         if grid[k][j] != 'W':
    15                             colhits[j] += grid[k][j] =='E'
    16                         else:
    17                             break
    18                 if not j or grid[i][j-1]=='W':
    19                     rowhits = 0
    20                     for k in range(j,n):
    21                         if grid[i][k]!='W':
    22                             rowhits += grid[i][k] == 'E'
    23                         else:
    24                             break
    25                 if grid[i][j] == '0':
    26                     res = max(res, colhits[j] + rowhits)
    27         return res

     


    368. Largest Divisible Subset 【Medium】  返回目录


     题目:

     

     解题思路:

    因为要两两互余,所以如果想要新加入一个新的数字到已确定的集合中,要么这个数字可以被集合中最小的数字除尽,要么就是可以可以除以尽最大的数,要么加大数进去,要么加小数进去,看自己的安排。

    用小数更好点,因为可以保持顺序

    为了之后能够很好的把结果找出来,所以还需要一个parent数组进行记录

    T[i]记录的是nums[i]为构成数组的最小数组的长度

     1 def largestDivisibleSubset(self, nums):
     2         """ 
     3         :rtype: List[int]
     4         """
     5         nums.sort()
     6         n = len(nums)
     7         T = [0 for i in range(n)]
     8         parent = [0 for i in range(n)]
     9         m = 0
    10         mi = 0
    11         for i in range(n-1,-1,-1):
    12             for j in range(i,n):
    13                 if nums[j] % nums[i] == 0 and T[i] < 1+T[j]:
    14                     T[i] = 1 + T[j]
    15                     parent[i] = j
    16                     if T[i] > m:
    17                         m = T[i]
    18                         mi = i
    19         res = []
    20         for i in range(m):
    21             res.append(nums[mi])
    22             mi = parent[mi]
    23         return res


    375. Guess Number Higher or Lower II 【Medium】  返回目录


     题目:

     解题思路:

    题目我都不甚理解,只能看答案进行辅助理解了。

    for k in [i,j]:  

      min(k+max(DP(i,k-1),DP(k+1,j)))

    0,n中要考虑第一次选择每一个数k的情况,这里综合选取最小的,为自己省钱,然而必须要考虑每次选取的最坏情况也就是之后的max函数

    这里就有两种解法,一个递归,一个动规, 动态规划其实就是递归的bottom-up实现,  递归是up-to-bottom

    code:  递归   太慢了,才beat 2%

     1 class Solution:
     2     def getMoneyAmount(self, n):
     3         """
     4         :type n: int
     5         :rtype: int
     6         """
     7         table = [[0 for j in range(n+1)] for i in range(n+1)]
     8         return self.dp(table, 1, n)
     9     def dp(self, t, s, e):
    10         if s >= e:
    11             return 0
    12         if t[s][e]!=0:
    13             return t[s][e]
    14         res = (e-s)*(s+e)//2+1
    15         for x in range(s,e+1):
    16             tmp = x + max(self.dp(t,s,x-1),self.dp(t,x+1,e))
    17             res = min(res,tmp)
    18         t[s][e] = res
    19         return res
    20         

    动态规划:  beat 50%

     1 def getMoneyAmount(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         dp = [[0 for j in range(n+1)] for i in range(n+1)]
     7         for j in range(2,n+1):
     8             for i in range(j-1,0,-1):
     9                 res = j*(j+1)/2
    10                 for k in range(i+1,j):
    11                     tmp = k + max(dp[i][k-1], dp[k+1][j])
    12                     res = min(res, tmp)
    13                 dp[i][j] = i if i+1==j else res
    14         return dp[1][n]


    376. Wiggle Subsequence 【Medium】   返回目录


    题目:

    解题思路:

    居然自己AC了,感动,用了很愚笨的方法  O(n^2) time O(n) space

     1 def wiggleMaxLength(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if n < 2:
     8             return n
     9         pos = [0 for i in range(n)]
    10         neg = [0 for j in range(n)]
    11         for i in range(1,n):
    12             for j in range(i):    
    13                 if nums[i]-nums[j]>0:
    14                     pos[i] = max(neg[j] + 1, pos[i])
    15                 elif nums[i]-nums[j]<0:
    16                     neg[i] = max(pos[j] + 1, neg[i])
    17         return max(pos[n-1],neg[n-1])+1
    18                 

    我没想出O(n) 的算法,参考答案:就在我的代码上做了小改进

     1 def wiggleMaxLength(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if n < 2:
     8             return n
     9         pos = [0 for i in range(n)]
    10         neg = [0 for j in range(n)]
    11         for i in range(1,n): 
    12             if nums[i]-nums[i-1] > 0:
    13                 pos[i] = neg[i-1] + 1
    14                 neg[i] = neg[i-1]
    15             elif nums[i]-nums[i-1]<0:
    16                 neg[i] = pos[i-1] + 1
    17                 pos[i] = pos[i-1]
    18             else:
    19                 neg[i] = neg[i-1]
    20                 pos[i] = pos[i-1]
    21         return max(pos[n-1],neg[n-1])+1
    22                 
    23         

    还可以再改进成O(1) space

     1 def wiggleMaxLength(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: int
     5         """
     6         n = len(nums)
     7         if n < 2:
     8             return n
     9         pos = 0
    10         neg = 0
    11         for i in range(1,n): 
    12             if nums[i]-nums[i-1] > 0:
    13                 pos = neg + 1
    14             elif nums[i]-nums[i-1]<0:
    15                 neg = pos + 1
    16         return max(pos, neg) + 1
    17                 


    377. Combination Sum IV  【Medium】   返回目录


    题目:

     解题思路:

    感觉就是一个递归和回溯,很快写完代码,但是TLE

     1 def combinationSum4(self, nums, target):
     2         """
     3         :type nums: List[int]
     4         :type target: int
     5         :rtype: int
     6         """
     7         if target == 0:
     8             return 1
     9         elif target < 0:
    10             return 0
    11         res = 0
    12         for i in nums:
    13             res += self.combinationSum4(nums,target-i)
    14         return res
    15         

    所以要看看有没有重复计算的部分,用动态规划记录中间结果

    dp[i]记录target为i的方法,然后求dp[target]

    居然过了!! O(target*n)  没有更好的方法了

     1 def combinationSum4(self, nums, target):
     2         """
     3         :type nums: List[int]
     4         :type target: int
     5         :rtype: int
     6         """
     7         dp = [0 for i in range(target+1)]
     8         for i in range(1,target+1):
     9             for num in nums:
    10                 if i-num == 0:
    11                     dp[i] = dp[i] + 1
    12                 elif i-num > 0:
    13                     dp[i] = dp[i] + dp[i-num]
    14         return dp[target]
    15                 

     


    392. Is Subsequence 【Medium】   返回目录


     题目:

     

     解题思路:

    暴力解法,居然过了嘿嘿   

     1 def isSubsequence(self, s, t):
     2         """
     3         :type s: str
     4         :type t: str
     5         :rtype: bool
     6         """
     7         begin = 0
     8         end = len(t)
     9         match = False
    10         for p in s:
    11             match = False
    12             for i in range(begin,end):
    13                 if p == t[i]:
    14                     match = True
    15                     begin = i+1
    16                     break
    17             if not match:
    18                 return False
    19         return True
    20         

    优化成 O(len(t))

     1 def isSubsequence(self, s, t):
     2         """
     3         :type s: str
     4         :type t: str
     5         :rtype: bool
     6         """
     7         i = j = 0
     8         m = len(s)
     9         if not m:
    10             return True
    11         n = len(t)
    12         while j < n:
    13             if s[i] == t[j]:
    14                 i += 1
    15                 if i == m:
    16                     return True
    17             j += 1
    18         return False


    413. Arithmetic Slices 【Medium】  返回目录


     题目:

     解题思路:

    我现在还挺厉害的,一遍过

     1 def numberOfArithmeticSlices(self, A):
     2         """
     3         :type A: List[int]
     4         :rtype: int
     5         """
     6         n = len(A)
     7         i = j = 0
     8         res = 0
     9         while j < n:
    10             while i + 2 < n:
    11                 if A[i+1]-A[i] == A[i+2]-A[i+1]:
    12                     break
    13                 else:
    14                     i += 1
    15             j = i + 2
    16             while j<n and (A[j]-A[j-1] == A[j-1]-A[j-2]):
    17                 res += j-i-1
    18                 j += 1
    19             i = j   
    20         return res

    我是以j为终点,到j的可行方案就是 j-i-1

    相同的时间复杂度,但是更为简洁的代码:

    参考答案

     1 def numberOfArithmeticSlices(self, A):
     2         """
     3         :type A: List[int]
     4         :rtype: int
     5         """
     6         curr = 0
     7         res = 0
     8         n = len(A)
     9         for i in range(2,n):
    10             if A[i]-A[i-1] == A[i-1]-A[i-2]:
    11                 curr += 1
    12                 res += curr
    13             else:
    14                 curr = 0
    15         return res


    416. Partition Equal Subset Sum 【Medium】   返回目录


     题目:

    解题思路:

    这其实是个求和问题,看数组中能否挑出数字的和为 target = sum/2 

    dp[target+1]

    for num in nums:

    for i in range(target,0,-1):

    dp[i] = dp[i] or dp[i-num]

     为什么不顺着来,因为顺着来的话比如 [1,2,5]   dp[2] = dp[1] 划分成1+1不对

    这样前面的不会重复

    def canPartition(self, nums):
            """
            :type nums: List[int]
            :rtype: bool
            """
            sums = sum(nums)
            if sums & 1:
                return False
            target = sum(nums)//2
            dp = [False for i in range(target+1)]
            dp[0] = True
            for num in nums:
                for i in range(target,num-1,-1):
                    dp[i] = dp[i] or dp[i-num]
            return dp[target]


    418. Sentence Screen Fitting 【Medium】【Locked】   返回目录


     题目:

    解题思路:

     说是Google的面试题

    参考答案的解法:用start变量来记录下能装下的句子的总长度,最后除以一个句子的长度(带空格),就可以得到个数。

    而句子的总长度的求法时需要在每个单词后面加上一个空格,包括最后一个单词,遍历屏幕的每一行,然后每次start都加上宽度,看all[start%len]是否为空格,如果是start+1,

     这个算法不容易理解,想到这个算法的人真的是太牛了。

     1 def wordsTyping(sentence, rows, cols):
     2         s = " ".join(sentence)
     3         s += " "
     4         n = len(s)
     5         start = 0
     6         for i in range(rows):
     7             start += cols
     8             if s[start % n] == " ":
     9                 start += 1
    10                 continue
    11             while start>0 and s[(start-1)%n]!=' ':
    12                 start -= 1
    13         return start // n

     


    464. Can I Win 【Medium】  返回目录


     题目:

    解题思路:

    对于Game playing的题目,用top-down DP做,每一个暴力的例子都是一种可能的游戏状态

    这种方式要注意的点就是注意不要重复求解子问题,时间复杂度可以从O(n!) 变到 O(2^n)  二叉树的子节点

    what is the state of the game?

     参考了一个答案,如下:

     1 class Solution:
     2     def canIWin(self, maxChoosableInteger, desiredTotal):
     3         """
     4         :type maxChoosableInteger: int
     5         :type desiredTotal: int
     6         :rtype: bool
     7         """
     8         if (1 + maxChoosableInteger)*maxChoosableInteger/2 < desiredTotal:
     9             return False
    10         self.memo = {}
    11         return self.helper(range(1,maxChoosableInteger+1),desiredTotal)
    12     
    13     def helper(self, nums,desiredTotal):
    14         nums = list(nums)
    15         hash_num = str(nums)
    16         if hash_num in self.memo:
    17             return self.memo[hash_num]
    18         if nums[-1] >= desiredTotal:
    19             return True
    20         for i in range(len(nums)):
    21             if not self.helper(nums[:i]+nums[i+1:], desiredTotal-nums[i]):
    22                 self.memo[hash_num] = True
    23                 return True
    24         self.memo[hash_num] = False
    25         return False

     


     467. Unique Substrings in Wraparound String 【Medium】   返回目录


     题目:

    解题思路:

    和之前有道题很相似,这里我给出了一种解法:

     1 def findSubstringInWraproundString(self, p):
     2         """
     3         :type p: str
     4         :rtype: int
     5         """
     6         n = len(p)
     7         res = len(set(p))
     8         i = j = 0
     9         for j in range(i+1,n):
    10             if ord(p[j]) == ord(p[j-1])+1 or ord(p[j]) == ord(p[j-1])-25:
    11                 res += (j-i)
    12             else: 
    13                 i = j
    14         return res

    通过样例21/81不能通过abaab这种带重复的样例

    一下给出正确代码:

    def findSubstringInWraproundString(self, p):
            """
            :type p: str
            :rtype: int
            """
            count = [0 for i in range(26)]
            maxLengthCur = 0
            for i in range(len(p)):
                if i > 0 and (ord(p[i]) == ord(p[i-1])+1 or ord(p[i]) == ord(p[i-1])-25):
                    maxLengthCur += 1
                else:
                    maxLengthCur = 1
                index = ord(p[i]) - ord('a')
                count[index] = max(count[index],maxLengthCur)
            
            res = 0
            for i in range(26):
                res += count[i]
            return res

    或者

    def findSubstringInWraproundString(self, p):
            """
            :type p: str
            :rtype: int
            """
            count = [0 for i in range(26)]
            res = length = 0
            for i in range(len(p)):
                cur = ord(p[i]) - ord('a')
                if i > 0 and ord(p[i-1])!=(cur+26-1)%26+ord('a'):
                    length = 0
                length += 1
                if length > count[cur]:
                    res += length - count[cur]
                    count[cur] = length
            return res


    474. Ones and Zeroes  【Medium】  返回目录


     题目:

     解题思路:

    用dp[i][j]表示用i个0和j个1能组成的字符串个数

    dp[i][j] = max(dp[i-zeros][j-ones]+1, dp[i][j])

    注意到一个细节,如果单词正好由i个0和j个1组成,就会在本来的基础上进行吧加一操作,所以是逐渐累加的过程

    code:

     1 def findMaxForm(self, strs, m, n):
     2         """
     3         :type strs: List[str]
     4         :type m: int
     5         :type n: int
     6         :rtype: int
     7         """
     8         dp = [[0]*(n+1) for i in range(m+1)]
     9         for s in strs:
    10             zeros, ones = s.count('0'),s.count('1')
    11             for i in range(m,zeros-1,-1):
    12                 for j in range(n,ones-1,-1):
    13                     dp[i][j] = max(dp[i-zeros][j-ones]+1, dp[i][j])
    14         return dp[m][n]

    上面代码python2不会超时,python3会超时,不是很懂


    486. Predict the Winner 【Medium】   返回目录


    题目:

     解题思路:

    这道题不太会做,直接看的答案,不知道如何设计dp数组

    看了答案,发现这种交替的任务还是应该看成同一个问题,同一种操作,也就是是说都是挑最大的score,只不过对手挑的时候取个负值

    dp[i,j]=nums[i]dp[i+1][j],nums[j]dp[i][j1].

     code:

     1 def PredictTheWinner(self, nums):
     2         """
     3         :type nums: List[int]
     4         :rtype: bool
     5         """
     6         n = len(nums)
     7         dp = [[0]*n for i in range(n+1)]
     8         for i in range(n,-1,-1):
     9             for j in range(i+1, n):
    10                 a = nums[i] - dp[i+1][j]
    11                 b = nums[j] - dp[i][j-1]
    12                 dp[i][j] = max(a,b)
    13         return dp[0][n-1] >= 0


    494. Target Sum  【Medium】  返回目录


    题目:

     

     解题思路:

    对于这里动态规划题型,主要就是要写出它的状态转移方程,也就是要自己定义好 dp[i][j] 其中i, j的意义,以及 dp[i][j]的意义

    通常情况下dp[i][j]是指要求的答案,i,j 是要自己设计它的意义,这里可以设i为  选择[0,i]个元素  j是指 和为j

    dp[i][j]表示 使用前i个数 的和达到 j 的总的方法数

    那么,

    dp[i][j] = dp[i-1][j-num[i]] + dp[i-1][j+num[i]] 

    边界条件是 初始全部为0 dp[0][num[0]] = 1   矩阵大小为 [len(num), max(sum(num),target)]

    j-num[i]  或者  j+num[i] 是要大于0的

    问题,对于第一个取负的情况处理不了  下面这个没有处理负数情况

     1 def findTargetSumWays(self, nums, S):
     2         """
     3         :type nums: List[int]
     4         :type S: int
     5         :rtype: int
     6         """
     7         n = len(nums)
     8         m = max(sum(nums),S)
     9         dp = [[0]*(m+1) for i in range(n)]
    10         dp[0][nums[0]] = 1
    11         for i in range(1,n):
    12             for j in range(m+1):
    13                 if j-nums[i]>=0:
    14                     dp[i][j] += dp[i-1][j-nums[i]]
    15                 if j+nums[i] <= m:
    16                     dp[i][j] += dp[i-1][j+nums[i]]
    17         print(dp)
    18         return dp[n-1][S]

    code:  利用上题目给出的限制条件,

    1. The sum of elements in the given array will not exceed 1000.
     1 def findTargetSumWays(self, nums, S):
     2         """
     3         :type nums: List[int]
     4         :type S: int
     5         :rtype: int
     6         """
     7         n = len(nums)
     8         dp = [[0]*2001 for i in range(n)]
     9         dp[0][nums[0]+1000] = 1
    10         dp[0][-nums[0]+1000] += 1
    11         for i in range(1,n):
    12             for j in range(-1000,1001):
    13                 if dp[i-1][j+1000]>0:
    14                     dp[i][j+nums[i]+1000] += dp[i-1][j+1000]
    15                     dp[i][j-nums[i]+1000] += dp[i-1][j+1000]
    16         return 0 if S>1000 else dp[n-1][S+1000]


     516. Longest Palindromic Subsequence 【Medium】  返回目录


    题目:

    解题思路:

    如果 c[i] == c[j]

    dp[i][j] = dp[i+1][j-1] + 2

    else: dp[i][j] = max(dp[i+1][j], dp[i][j-1])

    code:

     1 def longestPalindromeSubseq(self, s):
     2         """
     3         :type s: str
     4         :rtype: int
     5         """
     6         n = len(s)
     7         dp = [[1 if j==(i+1) else 0 for j in range(n+1)] for i in range(n)]
     8         for i in range(n-2,-1,-1):
     9             for j in range(i+2,n+1): 
    10                 if s[i] == s[j-1]:
    11                     dp[i][j] = dp[i+1][j-1] + 2
    12                 else:
    13                     dp[i][j] = max(dp[i][j-1],dp[i+1][j])
    14         return dp[0][n]

    这个代码超时了,不懂为什么

    code: JAVA Accepted

     1 public class Solution {
     2     public int longestPalindromeSubseq(String s) {
     3         int[][] dp = new int[s.length()][s.length()];
     4         
     5         for (int i = s.length() - 1; i >= 0; i--) {
     6             dp[i][i] = 1;
     7             for (int j = i+1; j < s.length(); j++) {
     8                 if (s.charAt(i) == s.charAt(j)) {
     9                     dp[i][j] = dp[i+1][j-1] + 2;
    10                 } else {
    11                     dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
    12                 }
    13             }
    14         }
    15         return dp[0][s.length()-1];
    16     }
    17 }


    523. Continuous Subarray Sum 【Medium】  返回目录


     题目:

     解题思路:

    暴力搜索,就会超时,以下是暴力搜索

    code:

     1 def checkSubarraySum(self, nums, k):
     2         """
     3         :type nums: List[int]
     4         :type k: int
     5         :rtype: bool
     6         """
     7         n = len(nums)
     8         for i in range(n-1):
     9             for j in range(i+1,n):
    10                 temp = sum(nums[i:j+1])
    11                 if not k:
    12                     if not temp:
    13                         return True
    14                     else:
    15                         return False
    16                 elif temp % k == 0:
    17                     return True
    18         return False

     看了下解题答案,真是太厉害了,用O(n)的时间复杂度只扫一遍就可以确定

    用hashmap记录下 累积到当前位置的和 mod k的余数对应的位置i

    如果累积和到位置j mod k相应余数和之前 位置i的相应余数相同,那么就说明 i-j之间的累积和 是k的倍数,注意在python中 hashmap用 dict表示

    code:

     1 def checkSubarraySum(self, nums, k):
     2         """
     3         :type nums: List[int]
     4         :type k: int
     5         :rtype: bool
     6         """
     7         hashmap = {0:-1}
     8         temp = 0
     9         for i in range(len(nums)):
    10             temp += nums[i]
    11             if k!=0:
    12                 temp = temp % k
    13             if temp in hashmap:
    14                 if i - hashmap[temp] > 1:
    15                     return True
    16             else:
    17                 hashmap[temp] = i
    18         return False

    这里还有个值的注意的点就是它对于0的处理,这里初始化为0 : -1

    所以,对于  [0,0] 0 的情况是正确的


    576. Out of Boundary Paths 【Medium】   返回目录


    题目:

    解题思路:

    什么情况下可以跨越边界,就是在倒数第一步的时候就在边界旁边,所以设置dp[i][j] 表示当前步数到(i,j)位置可能的path数目, 那么下一步的 (i,j) 位置就是上一步的它的上下左右位置的path数之和

     code:

     1 def findPaths(self, m, n, N, i, j):
     2         """
     3         :type m: int
     4         :type n: int
     5         :type N: int
     6         :type i: int
     7         :type j: int
     8         :rtype: int
     9         """
    10         M = 10**9 + 7
    11         dp = [[0]*n for i in range(m)]
    12         dp[i][j] = 1
    13         count = 0
    14         for k in range(1,N+1):
    15             temp = [[0]*n for i in range(m)]
    16             for i in range(m):
    17                 for j in range(n):
    18                     if i == m - 1:
    19                         count = (count + dp[i][j]) % M
    20                     if j == n - 1:
    21                         count = (count + dp[i][j]) % M
    22                     if i == 0:
    23                         count = (count + dp[i][j]) % M
    24                     if j == 0:
    25                         count = (count + dp[i][j]) % M
    26                     temp[i][j] = ((dp[i-1][j] if i>0 else 0) + (dp[i+1][j] if i<m-1 else 0) + (dp[i][j-1] if j>0 else 0) + (dp[i][j+1] if j < n-1 else 0)) % M
    27             dp = temp[:][:]
    28         return count

     


    638. Shopping Offers 【Medium】  返回目录


    题目:

     

    解题思路:

    不会做,只能看答案了

    code:

     1 def shoppingOffers(self, price, special, needs):
     2         """
     3         :type price: List[int]
     4         :type special: List[List[int]]
     5         :type needs: List[int]
     6         :rtype: int
     7         """
     8         d = {}
     9         def dfs(cur):
    10             val = sum(cur[i]*price[i] for i in range(len(needs))) #cost without special
    11             for spec in special:
    12                 tmp = [cur[j] - spec[j] for j in range(len(needs))]
    13                 if min(tmp) >= 0: 
    14                     val = min(val, d.get(tuple(tmp), dfs(tmp)) + spec[-1]) 
    15             d[tuple(cur)] = val
    16             return val
    17         return dfs(needs)

     


    646. Maximum Length of Pair Chain 【Medium】  返回目录


     题目:

     解题思路:

    首先 sort一遍这个列表,按照第二位数字的值进行升序排序

    dp[i]表示以i 结尾的 最长的chain长度,那么

    dp[i] = dp[nums[i][0]] + 1

    code:

     1 def findLongestChain(self, pairs):
     2         """
     3         :type pairs: List[List[int]]
     4         :rtype: int
     5         """
     6         pairs.sort()
     7         dp = [1] * len(pairs)
     8 
     9         for j in range(len(pairs)):
    10             for i in range(j-1,-1,-1):
    11                 if pairs[i][1] < pairs[j][0]:
    12                     dp[j] = max(dp[j], dp[i] + 1)
    13                     break
    14         return max(dp)

     看答案,用greedy贪心算法也行,有点像之前学的那个教室排课的算法(时间快了很多很多)

    1 def findLongestChain(self, pairs):
    2     cur, res = float('-inf'), 0
    3     for p in sorted(pairs, key=lambda x: x[1]):
    4         if cur < p[0]: cur, res = p[1], res + 1
    5     return res


    647. Palindromic Substrings 【Medium】  返回目录


     题目:

    解题思路:

    之前做过找最长的回文子序列,所以这道题很容易就能做出来

    用dp[i][j] 表示  i,j是否可以构成回文子序列

    code:

     1 def countSubstrings(self, s):
     2         """
     3         :type s: str
     4         :rtype: int
     5         """
     6         n = len(s)
     7         dp = [[1 if j==(i+1) or j==i else 0 for j in range(n+1)] for i in range(n)]
     8         for i in range(n-2, -1, -1):
     9             for j in range(i+2,n+1):
    10                 if s[i] == s[j-1]:
    11                     dp[i][j] = dp[i+1][j-1]
    12         return sum(sum(i) for i in dp) - n


    650. 2 Keys Keyboard 【Medium】  返回目录


    题目:

     解题思路:

    不会做,看了答案

    可以把这个问题形式化成一个素数分解问题

    code:

     1 def minSteps(self, n):
     2         """
     3         :type n: int
     4         :rtype: int
     5         """
     6         ans = 0 
     7         d = 2
     8         while n > 1:
     9             while n % d == 0:
    10                 ans += d
    11                 n /= d
    12             d += 1
    13         return ans


    651. 4 Keys Keyboard 【Medium】  返回目录  [locked]


    题目:

     

    解题思路:

    code:

    1 def maxA(self, N):
    2         best = [0, 1]
    3         for k in xrange(2, N+1):
    4             best.append(max(best[x] * (k-x-1) for x in xrange(k-1)))
    5             best[-1] = max(best[-1], best[-2] + 1) #addition
    6         return best[N]


     673. Number of Longest Increasing Subsequence  【Medium】  返回目录


     题目:

     解题思路:

    查看答案:

    code:

     1 def findNumberOfLIS(self, nums):
     2         N = len(nums)
     3         if N <= 1: return N
     4         lengths = [0] * N #lengths[i] = longest ending in nums[i]
     5         counts = [1] * N #count[i] = number of longest ending in nums[i]
     6 
     7         for j, num in enumerate(nums):
     8             for i in xrange(j):
     9                 if nums[i] < nums[j]:
    10                     if lengths[i] >= lengths[j]:
    11                         lengths[j] = 1 + lengths[i]
    12                         counts[j] = counts[i]
    13                     elif lengths[i] + 1 == lengths[j]:
    14                         counts[j] += counts[i]
    15 
    16         longest = max(lengths)
    17         return sum(c for i, c in enumerate(counts) if lengths[i] == longest)

     


    688. Knight Probability in Chessboard  【Medium】   返回目录


    题目:

     解题思路:

    利用两个棋盘,其中一个保存上一步的情况,每一个位置都是这一步在这个位置的概率,最后对棋盘求个总和就行

    代码看的答案,写的非常好

    code:

     1 def knightProbability(self, N, K, r, c):
     2         """
     3         :type N: int
     4         :type K: int
     5         :type r: int
     6         :type c: int
     7         :rtype: float
     8         """ 
     9         dp = [[0] * N for _ in xrange(N)]
    10         dp[r][c] = 1
    11         for _ in xrange(K):
    12             dp2 = [[0] * N for _ in xrange(N)]
    13             for r, row in enumerate(dp):
    14                 for c, val in enumerate(row):
    15                     for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
    16                                    (1,2),(1,-2),(-1,2),(-1,-2)):
    17                         if 0 <= r + dr < N and 0 <= c + dc < N:
    18                             dp2[r+dr][c+dc] += val / 8.0
    19             dp = dp2
    20 
    21         return sum(map(sum, dp))


    698. Partition to K Equal Sum Subsets 【Medium】   返回目录


     题目:

     


     712. Minimum ASCII Delete Sum for Two Strings 【Medium】    返回目录


     题目:


     740. Delete and Earn 【Medium】   返回目录


     题目:

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/lainey/p/8084643.html
Copyright © 2011-2022 走看看