面試算法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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章