问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
测试样例
样例1:
输入:
n = 5, k = 2, s = "01010"输出:00101
样例2:
输入:
n = 7, k = 3, s = "1101001"输出:0110101
样例3:
输入:
n = 4, k = 1, s = "1001"输出:0101
思路:
-
整体思路
- 核心思路:通过尝试所有可能的相邻字符交换操作(最多
k次),找到最终字典序最小的字符串。
- 核心思路:通过尝试所有可能的相邻字符交换操作(最多
-
具体分析
-
枚举所有交换情况
- 由于每次操作只能交换相邻的两个字符,并且最多可以进行
k次操作,所以这个问题可以看作是一个搜索问题,从初始字符串开始,逐步尝试不同的交换操作。 - 例如:对于字符串长度为
n,在每一步我们有n - 1种可能的相邻交换操作。如果我们把每一次交换看作是一个选择,总共需要做出最多k次选择来找到最小字典序的字符串。
- 由于每次操作只能交换相邻的两个字符,并且最多可以进行
-
递归实现方式
-
递归方式:
- 从原始字符串开始,每次进行一次相邻字符交换操作,然后递归地调用函数处理交换后的字符串,并且减少剩余的交换次数
k。 - 递归的终止条件是当剩余的交换次数为0时,此时比较当前得到的字符串与之前找到的最小字典序字符串,如果更小则继续更新。
- 从原始字符串开始,每次进行一次相邻字符交换操作,然后递归地调用函数处理交换后的字符串,并且减少剩余的交换次数
-
-
代码实现:
def solution(n: int, k: int, s: str) -> str:
min_str = s
def swap(lst, i, j):
new_lst = lst.copy()
new_lst[i], new_lst[j] = new_lst[j], new_lst[i]
return ''.join(new_lst)
def find_min_str(cur_s, k):
if k == 0:
return cur_s
min_cur_s = cur_s
for i in range(len(cur_s)-1):
new_s = swap(list(cur_s), i, i + 1)
sub_min_s = find_min_str(new_s, k - 1)
if sub_min_s < min_cur_s:
min_cur_s = sub_min_s
return min_cur_s
min_str = find_min_str(s, k)
return min_str
if __name__ == '__main__':
print(solution(5, 2, "01010") == '00101')
print(solution(7, 3, "1101001") == '0110101')
print(solution(4, 1, "1001") == '0101')
-
核心函数分析
-
find_min_str函数-
这个函数是核心的递归函数,用于寻找经过
k次交换后的最小字典序字符串。 -
递归情况:
- 首先将当前的最小字符串设为当前传入的字符串
cur_s,即min_cur_s = cur_s。 - 然后遍历当前字符串
cur_s的每个位置(除了最后一个位置,即for i in range(len(cur_s)-1))。 - 在每次遍历中,通过调用
swap函数交换当前位置i和下一个位置i + 1的字符,得到新的字符串new_s。 - 接着,递归调用
find_min_str函数,传入新字符串new_s和剩余交换次数减1(k - 1),得到经过k - 1次交换后的最小字典序字符串sub_min_s。 - 如果
sub_min_s的字典序小于当前的最小字符串min_cur_s(在Python中,字符串比较是基于字典序的),则更新min_cur_s为sub_min_s。 - 在遍历完所有可能的交换后,返回找到的最小字典序字符串
min_cur_s。
- 首先将当前的最小字符串设为当前传入的字符串
-
-
-
solution函数整体逻辑- 在
solution函数中,首先将最小字符串min_str初始化为输入字符串s。 - 然后调用
find_min_str函数,传入输入字符串s和可交换次数k,得到经过k次交换后的最小字典序字符串,将结果重新赋值给min_str。 - 最后返回这个最小字典序字符串
min_str。
- 在
感悟
- 递归是这段代码的灵魂所在。当剩余交换次数
k为0时,此时直接返回当前的字符串,这是递归的边界条件,它为整个递归过程提供了终止的依据。 - 在每次递归中,函数尝试通过交换相邻字符来探索所有可能的路径。它先将当前最小字符串设为当前字符串,然后遍历当前字符串的每个可能的交换位置,每次交换后递归地调用自身,减少剩余的交换次数。利用递归的特性巧妙的将一个复杂的多步操作问题逐步分解为一个个简单的子问题