返回

拨开数字组合的层层迷雾,洞悉数位 DP + 二分的奥秘

后端

LeetCode 902. 最大为 N 的数字组合

题目
来到 LeetCode 902. 最大为 N 的数字组合 这道难题面前,您将面临一个数字组合的生成任务,需要严格遵循给定的规则:

  1. 组合中的数字必须从 0 到 9 中选取。
  2. 数字只能使用一次。
  3. 组合中的数字必须按非递减顺序排列。

现在,给定一个整数 N,您的目标是生成一个满足以上规则的最大数字组合,并返回这个组合。

举个例子

比如,当 N = 2019 时,生成的组合应为「9120」,这是满足题目要求的最大组合。

解题思路

要解开这道难题,我们首先需要回顾一下经典的「数位 DP + 二分」组合算法。这是一套巧妙的组合生成方法,通过动态规划和二分查找相结合,可以有效地解决这类数字组合问题。

  1. 数位 DP:

    • 首先,我们需要将 N 分解成各个数位。例如,N = 2019 可以分解为 [2, 0, 1, 9]。
    • 然后,我们以每个数位作为分界线,将数字组合分成若干个子问题。
    • 对于每个子问题,我们都使用动态规划的方式来计算出所有满足要求的数字组合。
  2. 二分查找:

    • 在动态规划计算过程中,当我们需要在候选数字中选取一个数字时,可以使用二分查找算法来快速找到符合条件的最大数字。
    • 二分查找的效率远高于线性查找,可以大幅减少计算时间。
  3. 组合生成:

    • 最后,我们只需要将各个子问题的解组合在一起,就可以得到最终的数字组合。

代码实现

def largestNumber(N):
    """
    :type N: int
    :rtype: str
    """
    # 将 N 分解成各个数位
    digits = [int(d) for d in str(N)]

    # 子问题集合,key 为分界线数位,value 为满足要求的数字组合
    subproblems = {}

    # 计算每个子问题的解
    for i in range(len(digits)):
        subproblems[i] = digit_dp(digits, i)

    # 组合生成
    result = []
    for i in range(len(digits)):
        result.extend(subproblems[i])

    # 返回结果
    return ''.join(map(str, result))


def digit_dp(digits, boundary):
    """
    计算满足要求的数字组合
    :param digits: 数字列表
    :param boundary: 分界线数位
    :return: 满足要求的数字组合
    """
    # 备忘录,key 为候选数字,value 为满足要求的数字组合
    memo = {}

    def dp(index, prev_digit):
        if index == boundary:
            return ['']

        # 如果已经计算过,直接返回结果
        if (index, prev_digit) in memo:
            return memo[(index, prev_digit)]

        result = []

        # 从候选数字中选取一个数字
        for digit in range(prev_digit + 1, 10):
            if digit in digits:
                # 将选取的数字添加到组合中
                for combination in dp(index + 1, digit):
                    result.append(str(digit) + combination)

        # 将结果保存到备忘录中
        memo[(index, prev_digit)] = result

        # 返回结果
        return result

    # 返回初始状态的解
    return dp(0, -1)


if __name__ == "__main__":
    N = 2019
    print(largestNumber(N))

结语

LeetCode 902. 最大为 N 的数字组合 是一道充满挑战的算法题,需要您熟练掌握「数位 DP + 二分」组合算法。通过这道题的历练,相信您对算法的理解会更上一层楼。继续探索算法世界的奥秘,您将收获更多惊喜和成就感。