动态规划(一)

这里写图片描述

Coin Change

转移方程:
f(x) f ( x ) :amount x x 需要的最少硬币数。

f(x)=min(f(x1),f(x2),f(x5))+1

初值:

f(0)=0 f ( 0 ) = 0

def coinChange(coins, amount):
        # write your code here
        num=[float('inf')]*(amount+1)
        num[0]=0
        for i in range(amount+1):
            for money in coins:
                if i>=money:
                    num[i]=min(num[i],num[i-money]+1)
        if num[-1]==float('inf'):
            return -1

        return num[-1]
Paint House

fred(n)fgreen(n)fblue(n)=min(fblue(n1)+fgreen(n1))+costred=min(fblue(n1)+fred(n1))+costgreen=min(fred(n1)+fgreen(n1))+costblue f r e d ( n ) = m i n ( f b l u e ( n − 1 ) + f g r e e n ( n − 1 ) ) + c o s t r e d f g r e e n ( n ) = m i n ( f b l u e ( n − 1 ) + f r e d ( n − 1 ) ) + c o s t g r e e n f b l u e ( n ) = m i n ( f r e d ( n − 1 ) + f g r e e n ( n − 1 ) ) + c o s t b l u e

def minCost(costs):
        # write your code here
        if not costs:
            return 0
        n=len(costs)
        minCost0=[0]*n
        minCost1=[0]*n
        minCost2=[0]*n
        for i in range(n):
            if i==0:
                minCost0[i]=costs[0][0]
                minCost1[i]=costs[0][1]
                minCost2[i]=costs[0][2]
            else:
                minCost0[i]=min(minCost1[i-1],minCost2[i-1])+costs[i][0]
                minCost1[i]=min(minCost0[i-1],minCost2[i-1])+costs[i][1]
                minCost2[i]=min(minCost0[i-1],minCost1[i-1])+costs[i][2]
        return min(minCost0[-1],minCost1[-1],minCost2[-1])

Longest Increasing Continuous Subsequence

 def longestIncreasingContinuousSubsequence(lst):
        if not lst:
            return 0
        ret_increase=[1]*len(lst) #以自己结尾的最长连续子序列
        ret_decrease=[1]*len(lst)
        for i in range(len(lst)):
            if i>=1:
               if lst[i]>lst[i-1]:
                    ret_increase[i]=ret_increase[i-1]+1
               elif lst[i]<lst[i-1]:
                   ret_decrease[i]=ret_decrease[i-1]+1
        return max(max(ret_decrease),max(ret_increase))

Counting Bits

f(x)=f(x>>1)+mod(x,2) f ( x ) = f ( x >> 1 ) + m o d ( x , 2 )

def countingBits(num):
    ret=[0]*(num+1)
    for i in range(1,num+1):
        ret[i]=ret[i>>2]+i%2
    return ret

Paint House 2

i i 个房子涂第k种颜色的最小费用:

f(i,k)=minmk(f(i1,m))+cost[i][k]f(0,k)=cost[0][k] f ( i , k ) = m i n m ≠ k ( f ( i − 1 , m ) ) + c o s t [ i ] [ k ] f ( 0 , k ) = c o s t [ 0 ] [ k ]

class Solution:
    """
    @param costs: n x k cost matrix
    @return: an integer, the minimum cost to paint all houses
    """
    def minCostII(self, costs):
        # write your code here

        if not costs:
            return 0
        if not costs[0]:
            return 0

        N=len(costs)
        K=len(costs[0])
        money=[[0]*(K) for _ in range(N+1)]
        for n in range(1,N+1):
            for k in range(K):
                money[n][k]=float('inf')
                for j in range(K):
                    if j!=k:
                        money[n][k]=min(money[n-1][j]+costs[n-1][k],money[n][k])

        return min(money[-1])

直接遍历的话,时间复杂度为 O(nk2) O ( n k 2 ) ,运行超时。
优化算法:
计算第 i i 个房子涂色需要的最小费用时,我们需要记录f(i1)的最小两个值,时间复杂度变为 O(nk) O ( n k )

class Solution:
    """
    @param costs: n x k cost matrix
    @return: an integer, the minimum cost to paint all houses
    """
    def minCostII(self, costs):
        # write your code here

        if not costs:
            return 0
        if not costs[0]:
            return 0

        N=len(costs)
        K=len(costs[0])
        money=[[0]*(K) for _ in range(N+1)]

        for n in range(1,N+1):
            #找到上一轮最小的两个值
            min1=float('inf')
            min2=float('inf')
            j1=-1; j2=-1
            for k in range(K):
                if money[n-1][k]<min1:
                    min2=min1
                    j2=j1
                    min1=money[n-1][k]
                    j1=k
                elif money[n-1][k]<min2:
                    min2=money[n-1][k]
                    j2=k

            for k in range(K):
                if k!=j1:#如果k并不是上一轮最小的那个颜色,直接取最小值
                    money[n][k]=min1+costs[n-1][k]
                else:#如果k是上一轮最小的颜色,取第二小
                    money[n][k]=min2+costs[n-1][k]

        return min(money[-1])

House Robber 1

对于第 i i 栋房子,有两种选择,如果不偷,那么总共偷到的最多的钱和f(i1)一样,如果偷,那么总共偷到的最多的钱为 f(i2)+A[i] f ( i − 2 ) + A [ i ]

f(i)=max(f(i1),f(i2)+A[i]) f ( i ) = m a x ( f ( i − 1 ) , f ( i − 2 ) + A [ i ] )

class Solution:
    """
    @param A: An array of non-negative integers
    @return: The maximum amount of money you can rob tonight
    """
    def houseRobber(self, A):
        # write your code here
        if not A:
            return 0

        n=len(A)

        money=[e for e in A]
        for i in range(n):
            if i>=1:
                money[i]=max(money[i-1],money[i])#不偷
            if i>=2:
                money[i]=max(money[i-2]+A[i],money[i])#偷

        return money[-1]

House Robber 2

第0个和 n1 n − 1 不能同时偷。
这里写图片描述
这里写图片描述
这里写图片描述


参考资料:

侯卫东老师动态规划专题课程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值