Python 数据结构之动态规划

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haiyu94/article/details/79680224

目录

  1. 爬楼梯 (LeetCode 70)
  2. 打家劫舍 (LeetCode 198)
  3. 最大字段和(LeetCode 53)
  4. 找零钱(LeetCode 322)
  5. 三角形(LeetCode 120)
  6. 最长上升子序列 (LeetCode 300)
  7. 最小路径和(LeetCode 64)
  8. 地牢游戏(LeetCode 174)

1.动态规划的基本思想

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。

2. 爬楼梯 (LeetCode 70 Climbing Stairs)

2.1题目

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

Example 1:

Input: 2
Output:  2
Explanation:  There are two ways to climb to the top.

1. 1 step + 1 step
2. 2 steps

Example 2:

Input: 3
Output:  3
Explanation:  There are three ways to climb to the top.

1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step

2.2思路

楼梯共有n层台阶,每一步共有两种走法:1步或2步
如果n<=1,则只有一种方法
第n层的走法数等于的第n-1层的走法总数+第n-2层的走法总数,因为每次共有两种走法,1步或者2步。
temp1表示第n-1层的走法数,temp2表示第n-2层的走法数
初始化为1,i表示当前所在的台阶数

2.3代码

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1 or n == 0:
            return 1
        i = 2
        temp1 = 1
        temp2 = 1
        while i <= n:
            temp1 += temp2
            if i == n:
                return temp1
            i += 1
            temp2 += temp1
            if i == n:
                return temp2
            i += 1

3. 打家劫舍 (LeetCode 198 House Robber)

3.1题目

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Credits:

3.2思路

对每一个住户,小偷有两种选择,偷或者不偷
ans0:表示不偷当前的住户,其最大收益
ans1:表示偷当前的住户,其最大收益
temp= ans0:不偷上一个住户的最大收益
ans0=max(ans0,ans1)
ans1=temp + nums[i]

3.3代码

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        ans0 = 0
        ans1 = 0
        for i in range(0,len(nums)):
            temp = ans0
            ans0 = max(ans0,ans1)
            ans1 = temp + nums[i]
        return max(ans0,ans1)

4. 最大字段和(LeetCode 53Maximum Subarray)

4.1题目

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

4.2思路

cursum:表示当前和
maxsum:表示最大和

c u r s u m = m a x ( c u r s u m + n u m s [ i ] , n u m s [ i ) m a x s u m = m a x ( m a x s u m , c u r s u m )

4.3代码

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        cursum = nums[0]
        maxsum = nums[0]
        for i in range(1,size):
            cursum = max(cursum + nums[i], nums[i])
            maxsum = max(maxsum, cursum)
        return maxsum

5. 找零钱(LeetCode 322Coin Change)

5.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 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

5.2思路

dp[i]表示组成总钱数i所需的最小的硬币数量
对硬币列表中的硬币,dp[i]=min(dp[i-coin]+1)

5.3代码

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        MAX = float('inf')
        dp = [0] + [MAX] * amount

        for i in xrange(1, amount + 1):
            dp[i] = min([dp[i - c] if i - c >= 0 else MAX for c in coins]) + 1

        return [dp[amount], -1][dp[amount] == MAX]

6. 三角形(LeetCode 120 Triangle)

6.1题目

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

6.2思路

ans[i][j]:表示该位置路径的最小和

a n s [ i ] [ j ] = m i n ( a n s [ i 1 , j 1 ] , a n s [ i 1 ] [ j ] ) + t r [ i ] [ j ]

6.3代码

class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        n = len(triangle)
        if n == 1:
            if triangle[0] == []:
                return None
            return min(triangle[0])
        ans = [triangle[0]]
        for i in range(1,n):
            ans1 = []
            for j in range(0, i + 1):
                if j == 0:
                    ans1.append(ans[i-1][0] + triangle[i][j])
                elif j == i:
                    ans1.append(ans[i-1][i-1] + triangle[i][j])
                else:
                    ans1.append(min(ans[i-1][j-1],ans[i-1][j]) + triangle[i][j])
            ans.append(ans1)
        return min(ans[-1])

7. 最长上升子序列 (LeetCode 300Longest Increasing Subsequence)

7.1题目

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

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O( n 2 ) complexity.

7.2思路

dp[i]:表示到第i个元素为止,最长升序子序列的长度
初始化:dp[i]=1
将当前元素与之前的元素nums[j]进行比较,如果当前元素大于nums[j],则:

d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 )

返回dp中的最大值

7.3代码

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        if size == 0:
            return 0
        dp = [1 for i in range(size)]
        for i in range(1, size):
            for j in range(0, i):
                if nums[i] > nums[j] and dp[j] + 1 > dp[i]:
                    dp[i] = dp[j] + 1
        return max(dp)

8. 最小路径和(LeetCode 64Minimum Path Sum)

8.1题目

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example 1:

[[1,3,1],
 [1,5,1],
 [4,2,1]]

Given the above grid map, return 7. Because the path 1→3→1→1→1 minimizes the sum.

8.2思路

ans[i][j]:表示当前位置的最小和
ans[0][0]=grid[0][0]

a n s [ i ] [ j ] = m i n ( a n s [ i ] [ j 1 ] , a n s [ i 1 ] [ j ] ) + g r i d [ i ] [ j ]

8.3代码

class Solution(object):
    def minPathSum(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m = len(grid)
        n = len(grid[0])
        ans = [[0 for i in range(n)] for j in range(m)]
        ans[0][0] = grid[0][0]
        for i in range(0,m):
            for j in range(0,n):
                if i == 0 and j != 0:
                    ans[i][j] = ans[i][j-1] + grid[i][j]
                elif i != 0 and j == 0:
                    ans[i][j] = ans[i-1][j] + grid[i][j]
                elif i != 0 and j != 0:
                    ans[i][j] = min(ans[i-1][j],ans[i][j-1]) + grid[i][j]
        return ans[m-1][n-1]

9. 地牢游戏(LeetCode 174Dungeon Game)

9.1题目

The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0’s) or contain magic orbs that increase the knight’s health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight’s minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

-2(K)   -3    3
 -5     -10   1
 10     30  -5(P)

Notes:

The knight’s health has no upper bound.
Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

9.2思路

反向思路,从最下面一行往上计算,从每行最右边到最左边进行计算

n e e d [ i ] [ j ] = m a x ( m i n ( n e e d [ i ] [ j : j + 2 ] ) d u n g e o n [ i ] [ j ] , 1 )

初始化
n e e d [ m 1 ] = [ ] [ n ] , n e e d [ m 1 ] [ n 1 ] = 1

9.3代码

class Solution(object):
    def calculateMinimumHP(self, dungeon):
        """
        :type dungeon: List[List[int]]
        :rtype: int
        """
        n = len(dungeon[0])
        need = [2**31] * (n-1) + [1]
        for row in dungeon[::-1]:
            for j in range(n)[::-1]:
                need[j] = max(min(need[j:j+2]) - row[j], 1)
        return need[0]

猜你喜欢

转载自blog.csdn.net/haiyu94/article/details/79680224