算法-动态规划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)时,会因为耗时太长而通不过的。在前面提到的慕课网的课程里,是通过回溯法来解决的。我在这里,是借这个例子来实践前面学习到的动态规划的解题思路。

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