算法-動態規劃3

根據在算法-動態規劃2裏提到的思路,讓我們來解決一個組合問題 :leetcode 第77題

0 問題描述

給定2個整數n,k,求出從[1,…,n]中取k個數字的所有組合。
例如 n=4, k=2
就是從[1,2,3,4]中取2個數字的所有組合。
結果爲:[[1, 2], [1, 3], [2, 3], [1, 4], [2, 4], [3, 4]]

1 遞歸解法

(1)假設組合中不包含 第n個數字,原問題就變爲:

求出從[1,…,n-1] 中取k個數字的所有組合。

(2)假設組合中包含 第n個數字,原問題就變成了:

求出從[1,…,n-1]中取 k-1 個數字的組合,然後中每個組合中,把第n個數字加進去。

(1)+ (2)就是問題的解。

import copy


class Solution:
    def combine(self, n, k):
        return self.combine_core(n, k)

    def combine_core(self, n, k):
        if n <= 0 or k <= 0:
            return list()
        if k == 1:
            return [[i] for i in range(1, n + 1)]

		# 第(1)種情況
        res1 = self.combine_core(n - 1, k)

		# 第(2)種情況
        res2 = self.combine_core(n - 1, k - 1)
        # 把 第n個數字 加入(2)的結果中
        for l in res2:
            l.append(n)

		# (1)+(2)
        res = list()
        if res1:
            res.extend(res1)
        if res2:
            res.extend(res2)

        return res

# main
s = Solution()
print(s.combine(4, 2))


2 記憶化搜索解法

import copy


class Solution:
    def __init__(self):
        self.memo = list()

    def combine(self, n, k):
        self.memo = [[None for j in range(k+1)] for i in range(0, n+1)]
        return self.combine_core(n, k)

    def combine_core(self, n, k):
        if n <= 0 or k <= 0:
            return list()
        if k == 1:
            return [[i] for i in range(1, n + 1)]

		# 返回存儲的結果
        if self.memo[n][k] is not None:
            return self.memo[n][k]

        res1 = self.combine_core(n - 1, k)
        res2 = self.combine_core(n - 1, k - 1)
        for l in res2:
            l.append(n)

        res = list()
        if res1:
            res.extend(res1)
        if res2:
            res.extend(res2)
		# 存儲結果,因爲python的list賦值是對象引用的賦值,這裏需要用深拷貝
        self.memo[n][k] = copy.deepcopy(res)
        return res

3 動態規劃的解法

def combine(n, k):
    memo = [[list() for j in range(k + 1)] for i in range(0, n + 1)]

    for i in range(1, n+1):
        memo[i][1] = [[v] for v in range(1, i + 1)]

    for i in range(1, n+1):
        for j in range(1, k+1):
            res1 = memo[i - 1][j]
            res2 = memo[i - 1][j - 1]
            for l in res2:
                l.append(i)

            if not memo[i][j]:
                memo[i][j].extend(copy.deepcopy(res1))
                memo[i][j].extend(copy.deepcopy(res2))

    return memo[n][k]

# main
print(combine(4, 2))

注意:
這個動態規劃的解法,因爲涉及到list的深拷貝,所以會比較耗時。在leetcode上當跑到(20,16)時,會因爲耗時太長而通不過的。在前面提到的慕課網的課程裏,是通過回溯法來解決的。我在這裏,是借這個例子來實踐前面學習到的動態規劃的解題思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章