面试算法combine sum专题讲解二(动态规划法)

这一部分,我们将讲解DP问题求解combine sum的最优解问题。

涉及的代码题目是leetcode 377、322

leetcode 377

问题描述:整数数组,无重复元素,但每个数字可以被重复使用,给出组合的总数,无须给出所有排列。

算法设计思路:创建dp数组,dp[i]表示target为i时,无重复元素组合的总数。

算法实现:

class Solution(object):
    def combineSolution4(self, nums, target):
        nums.sort()
        dp = [0] * (target+1)
        dp[0] = 1
        for i in range(1, target+1):
            for num in nums:
                if i >= num:
                    dp[i] = dp[i] + dp[i-num]
                else:  # 剪枝
                    break
        result = dp[target]
        return result

demo测试以及结果:

if __name__ == '__main__':
    s = Solution()
    print(s.combineSolution4([1,2,3], 4))
7

leetcode 322

问题描述:

已知不同面值的钞票,求如何使用最少数量的钞票组成某个金额,钞票可重复使用。若任意数量的已知面值都无法组成该金额,直接返回0。举例如下:

钞票面值 [1,2,5],target=11,解=3(5+5+1)
钞票面值 [2],target=3,解=0(无法组成)
钞票面值 [1,2,5,7,10],target=14,解=2(7+7)

算法设计思路:

对于[1, 2, 5],target=11的问题,可用贪心策略求解得到最优解3,但是对于[1, 2, 5, 7, 10],target=14用贪心策略的结果3(10+2+2)就不是全局最优解,此时DP策略可以解决,创建dp数组,dp[i]表示组成金额i的最少钞票数量。

对于[1, 2, 5, 7, 10],target=14这个instance来说,dp[i]代表最优解,初始值都是-1(dp[0]——dp[14]=-1),计算dp[i]时,dp[0]~dp[i-1]都已经计算出来,它们之间的递推关系如何,尝试使用这些值递推。

dp[i-1] 与 coin[0] (1)组合;
dp[i-2] 与 coin[1] (2)组合;
dp[i-5] 与 coin[2] (5)组合;
dp[i-7] 与 coin[3] (7)组合;
dp[i-10] 与 coin[4] (10)组合

而状态i可由前面这5个状态(i-1,i-2,i-5,i-7,i-10)共同决定,即:

dp[i] = min{dp[i-1], dp[i-2], dp[i-5], dp[i-7], dp[i-10]}+1

算法实现:

def money_change(nums, target):
    dp = [0] * (target+1)   # dp
    for i in range(1, target+1):
        min = target
        for num in nums:
            if i >= num and dp[i-num] < min:
                min = dp[i-num]
        dp[i] = min+1
    return dp[target]

demo测试以及结果:

if __name__ == '__main__':
    r = money_change(nums=[1,2,5,7,10], target=14)
    print(r)
    r = money_change(nums=[1,2,5,7,10], target=18)
    print(r)
2
3

猜你喜欢

转载自blog.csdn.net/little_fire/article/details/80504890