[leetcode]中级算法——动态规划

跳跃游戏

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

Example:

Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Code(By myself):

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if nums[0] >= len(nums) - 1:
            return True
        elif nums[0] == 0:
            return False
        if 0 not in nums:
            return True
        else:
            for i in range(nums[0]+1):
                if nums[0] < nums[i]+i:
                    if self.canJump(nums[i:]):
                        return True
        return False
Code(others):
class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        n=len(nums)
        max_index=n-1
        for i in range(n-2,-1,-1):
            if i+nums[i]>=max_index:
                max_index=i
        return max_index==0
总结:

从后往前遍历,若能到达之后的点就前移

不同路径

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?



Above is a 7 x 3 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

Example:

Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right

Code(By myself):

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        # if n == 0 or m == 0:
        #     return 
        # if n == 1 or m == 1:
        #     return 1
        # if m == 2 and n == 2:
        #     return 2
        # if m == 3 and n == 2:
        #     return 3
        # if m == 2 and n == 3:
        #     return 3
        # else:
        #     return self.uniquePaths(m-1,n) + self.uniquePaths(m,n-1)
        matrix = [[0 for i in range(n)] for j in range(m)]
        for i in range(m):
            for j in range(n):
                if i == 0 or j == 0:
                    matrix[i][j] = 1
                else:
                    matrix[i][j] = matrix[i-1][j] + matrix[i][j-1]
        return matrix[m-1][n-1]

最先尝试用递归的方法进行求解,到达某点的步数为到达上方和左方步数之和,到达边界返回1,不过由于递归每次都重新探索,所以时间复杂度是结果数量的量级,而不是多项式的复杂度,因此时间超过了。

于是由于递推式已经得出,于是用一个m*n矩阵进行存储相应步数,时间复杂度为O(m*n)。空间复杂度为O(m*n)。该方法可以进一步优化用一个长度为min(m,n)的数组进行存储上一行/列的相应步数,递推式为res[i]+=res[i-1]不断重复更新,空间复杂度优化为O(min(m,n))。

Code(others):

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        j=min(m-1,n-1)
        if j==0:
            return 1
        k=m+n-2
        res1=1
        res2=1
        for i in range(j):
            res1*=k-i
            res2*=j-i
        return res1/res2

该动态规划可以理解为总共走了m+n-2步,选择其中m-1往下走,n-1往右走,这就变成了组合问题。选择min(m-1.n-1)进行计算即可,时间复杂度为O(min(m-1.n-1)),空间复杂度为O(1)。


零钱兑换

You are given coins of different denominations and a total amount of money  amount . Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return  -1 .

Example:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

Code(By myself):

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        if amount == 0:
            return 0
        index = [0 for i in range(amount + 1)]
        for i in coins:
            if i <= amount:
                index[i] = 1
        for i in range(1,amount+1):
            if index[i] == 0:
                continue
            for j in coins:
                if i + j <= amount and (index[i+j] == 0 or index[i+j] > index[i] + 1):
                    index[i+j] =index[i] + 1
        if index[amount] == 0:
            return -1
        return index[amount]
       
Code(others):
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """


        size = len(coins)
        if size == 0:
            return -1
        
        if amount == 0:
            return 0
        
        coins.sort(reverse=True)
        
        self.res = 2 ** 31
        
        def dfs(remain, idx, cnt):
            if remain == 0:
                self.res = min(self.res, cnt)
                return
            
            for i in range(idx, size):
                if coins[i] * (self.res - cnt)  < remain:
                    return
                elif coins[i] <= remain:
                    dfs(remain-coins[i], i, cnt+1)
        
        for i in range(size):
            if coins[i] * (self.res)  < amount:
                return self.res
            elif coins[i] <= amount:
                dfs(amount-coins[i], i, 1)
        
        return self.res if (self.res < 2**31) else -1
总结:

利用递归先将最大的硬币使用最多次数,若不行则减少一枚大的,利用小的凑齐。

最长上升子序列

Given an unsorted array of integers, find the length of longest increasing subsequence.

Example:

Input: [10,9,2,5,3,7,101,18]
Output: 4 
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. 

Code(By myself):

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 0:
            return 0
        maxLen = [1 for i in range(len(nums))]
        maxLen = self.length(nums,maxLen)
        return max(maxLen)
    
    def length(self,nums,maxLen):
        if len(nums) == 0:
            return maxLen
        if len(nums) == 1:
            maxLen[0] = max(maxLen[0],1)
            return maxLen
        maxLen[1:] = self.length(nums[1:],maxLen[1:])
        for i in range(1,len(nums)):
            if nums[0] < nums[i]:
                maxLen[0] = max(maxLen[0],maxLen[i]+1)
        return maxLen
Code(others):
import bisect
    
class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        q = [nums[0]]

        for n in nums[1:]:
            if n > q[-1]:
                q.append(n)
            else:
                p = bisect.bisect_left(q, n)
                q[p] = n

        return len(q)
class Solution(object):
    left = 0
    right = 0
    
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        
        """
        if nums==[]:
            return 0
        ends = []
        ends.insert(0,nums[0])
        for i in range(1,len(nums)):
            if nums[i]<ends[0]:
                ends[0]=nums[i]
            elif nums[i]>ends[-1]:
                ends.append(nums[i])
            else:
                l = 0
                r = len(ends)-1
                while l<r:
                    mid = (l+r)/2
                    if ends[mid]<nums[i]: 
                        l= mid + 1
                    else: 
                        r = mid
                ends[r] = nums[i]
        return len(ends)
总结:

建立一个子序列表,遍历nums(),比子序列表最后一个元素大就加到最后,其他时替换相应位置元素。最后得出的最长子序列不一定时正确的子序列,但其长度时最长的子序列长度。



Above is a 7 x 3 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值