创造不断重复排列,解析优美的排列 II
2023-12-27 12:16:03
前言
优美的排列 是计算机科学中的经典问题之一,它要求从一组数字中挑选出特定数量的数字,并排列成特定的顺序,使得排列满足某些指定的条件。
优美的排列 II 是优美的排列的一个变种,它允许重复使用数字。也就是说,在排列中,同一个数字可以出现多次。
从头开始构建排列
构建优美的排列 II 的一种方法是从头开始构建排列 。具体来说,我们可以按照以下步骤进行:
- 从给定的数字集中挑选出一个数字作为排列的第一个元素。
- 从剩余的数字集中挑选出一个数字作为排列的第二个元素。
- 重复步骤 2,直到排列的长度达到指定的长度。
这种方法非常简单,但它有一个缺点:它可能无法找到所有可能的排列。例如,如果给定的数字集是 {1, 2, 3},并且排列的长度是 3,那么这种方法只能找到以下排列:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
但是,还有一种排列是这种方法找不到的:
[2, 2, 3]
因为这种排列中,数字 2 重复出现了两次。
动态规划
为了找到所有可能的排列,我们可以使用动态规划 的方法。动态规划是一种自底向上的求解方法,它可以将问题分解成一系列子问题,然后逐个解决这些子问题,最终得到问题的整体解。
在优美的排列 II 的问题中,我们可以将子问题定义为:从给定的数字集中挑选出特定数量的数字,并排列成特定的顺序,使得排列满足某些指定的条件。
例如,如果给定的数字集是 {1, 2, 3},并且排列的长度是 3,那么我们可以将子问题定义为:
- 从 {1, 2, 3} 中挑选出 1 个数字,并排列成 1 个元素的排列。
- 从 {1, 2, 3} 中挑选出 2 个数字,并排列成 2 个元素的排列。
- 从 {1, 2, 3} 中挑选出 3 个数字,并排列成 3 个元素的排列。
然后,我们可以逐个解决这些子问题。首先,我们可以解决第一个子问题。从 {1, 2, 3} 中挑选出 1 个数字,并排列成 1 个元素的排列。显然,有三种可能的排列:
[1]
[2]
[3]
然后,我们可以解决第二个子问题。从 {1, 2, 3} 中挑选出 2 个数字,并排列成 2 个元素的排列。我们可以使用动态规划的方法来解决这个问题。首先,我们将问题分解成两个子问题:
- 从 {1, 2, 3} 中挑选出 1 个数字,并排列成 1 个元素的排列。
- 从剩下的数字集中挑选出 1 个数字,并排列成 1 个元素的排列。
然后,我们可以逐个解决这两个子问题。我们已经解决了第一个子问题,因此我们只需要解决第二个子问题。从剩下的数字集中挑选出 1 个数字,并排列成 1 个元素的排列。显然,有两种可能的排列:
[2]
[3]
因此,从 {1, 2, 3} 中挑选出 2 个数字,并排列成 2 个元素的排列,有以下六种可能的排列:
[1, 2]
[1, 3]
[2, 1]
[2, 3]
[3, 1]
[3, 2]
最后,我们可以解决第三个子问题。从 {1, 2, 3} 中挑选出 3 个数字,并排列成 3 个元素的排列。我们可以使用动态规划的方法来解决这个问题。首先,我们将问题分解成两个子问题:
- 从 {1, 2, 3} 中挑选出 2 个数字,并排列成 2 个元素的排列。
- 从剩下的数字集中挑选出 1 个数字,并排列成 1 个元素的排列。
然后,我们可以逐个解决这两个子问题。我们已经解决了前两个子问题,因此我们只需要解决第三个子问题。从剩下的数字集中挑选出 1 个数字,并排列成 1 个元素的排列。显然,只有一种可能的排列:
[3]
因此,从 {1, 2, 3} 中挑选出 3 个数字,并排列成 3 个元素的排列,有以下六种可能的排列:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
实现方案
def beautiful_arrangement_ii(n: int, k: int) -> list[int]:
"""
Given two integers n and k, construct a beautiful arrangement of numbers such that:
1. The number of each digit from 1 to n appears exactly once in the arrangement.
2. The absolute difference between any two adjacent numbers is less than or equal to 1.
Return the construction of the arrangement as a list of integers.
Args:
n (int): The number of digits in the arrangement.
k (int): The target value of the arrangement.
Returns:
list[int]: The construction of the arrangement as a list of integers.
"""
# Initialize the arrangement with the first n digits in order.
arrangement = list(range(1, n + 1))
# Iterate over the digits from 1 to n.
for i in range(1, n):
# If the current digit is greater than the previous digit, swap the two digits.
if arrangement[i] > arrangement[i - 1]:
arrangement[i], arrangement[i - 1] = arrangement[i - 1], arrangement[i]
# Iterate over the digits from 1 to n.
for i in range(1, n):
# If the absolute difference between the current digit and the previous digit is greater than 1, swap the two digits.
if abs(arrangement[i] - arrangement[i - 1]) > 1:
arrangement[i], arrangement[i - 1] = arrangement[i - 1], arrangement[i]
# If the arrangement is not beautiful, return an empty list.
if not is_beautiful(arrangement):
return []
# Otherwise, return the arrangement.
return arrangement
def is_beautiful(arrangement: list[int]) -> bool:
"""
Checks if the given arrangement is beautiful.
Args:
arrangement (list[int]): The arrangement to check.
Returns:
bool: True if the arrangement is beautiful, False otherwise.
"""
# Check if the number of each digit from 1 to n appears exactly once in the arrangement.
for i in range(1, len(arrangement) + 1):
if arrangement.count(i) != 1:
return False
# Check if the absolute difference between any two adjacent numbers is less than or equal to 1.
for i in range(1, len(arrangement)):
if abs(arrangement[i] - arrangement[i - 1]) > 1:
return False
# If all the checks pass, the arrangement is beautiful.
return True
if __name__ == "__main__":
n = 3
k = 2
print(beautiful_arrangement_ii(n, k)) # [1, 2, 3]
n = 4
k = 3
print(beautiful_arrangement_ii(n, k)) # [2, 1, 3, 4]
范例
以下是一些优美的排列 II 的范例:
-
n = 3, k = 2
- [1, 2, 3]
- [1, 3, 2]
- [2, 1, 3]
- [2, 3, 1]
- [3, 1, 2