字典序最小的01字符串|豆包MarsCode AI刷题

86 阅读4分钟

1.题目

2.思路

在有限的移动次数中,尽可能把0往前移

样例1:

输入:n= 5,k= 2,s="01010"

第一次移动 "00110"

第二次移动"00101"

输出::'00101'

问题理解

你需要通过最多 k 次相邻字符交换操作,使得给定的由 01 组成的字符串 s 的字典序最小。字典序最小意味着字符串中的 0 应该尽可能地排在前面, 1 应该尽可能地排在后面

数据结构选择

由于我们只需要处理字符串中的字符,并且字符串是不可变的,我们可以使用列表来存储字符串中的字符,以便于进行交换操作。

算法步骤

  1. 转换字符串为列表:将字符串 s 转换为列表 s_list,以便于进行交换操作。
  2. 贪心策略:从左到右遍历字符串,尝试将当前位置的 0 尽可能地向左移动,直到达到 k 次操作的限制。
  3. 交换操作:在遍历过程中,如果当前字符是 0,尝试将其向左移动,直到遇到另一个 0 或者达到 k 次操作的限制。
  4. 转换回字符串:完成所有操作后,将列表转换回字符串并返回。

3.代码

3.1从左往右遍历,遇到0向左移

def solution(n: int, k: int, s: str) -> str:
    # write code here
    s_list = list(s)
    swap_count = 0
    while swap_count < k:
        for i in range(n):
            # 当前字符为0,且不是第一个
            if s[i] == 0 and i != 0:
                # 和前一个交换
                s[i], s[i - 1] = s[i - 1], s[i]
    return str(s_list)

交换一次,swap_count+1,如果没有交换,会进入死循环,所以当for循环执行完,要跳出while循环

def solution(n: int, k: int, s: str) -> str:
    # write code here
    s_list = list(s)
    swap_count = 0
    while swap_count < k:
        for i in range(n):
            # 当前字符为0,且不是第一个
            if s[i] == 0 and i != 0:
                # 和前一个交换
                s[i], s[i - 1] = s[i - 1], s[i]
                swap_count += 1
        break
    return str(s_list)

不应该用while循环在外层控制结束,应在每次swap_count += 1时判断是否结束

def solution(n: int, k: int, s: str) -> str:
    # write code here
    s_list = list(s)
    swap_count = 1
    for i in range(n):
        # 当前字符为0,且不是第一个
        if s[i] == 0 and i != 0:
            # 和前一个交换
            s[i], s[i - 1] = s[i - 1], s[i]
            swap_count += 1
            if swap_count >= k:
                break
    return str(s_list)
  • 发现交换的时候忘了用s_list
  • if s_list[i] == 0 and i != 0:这里应该用's_list[i] == '0'
  • if swap_count >= k:改为if swap_count >= k:
  • 列表转字符串:string.join(iterable)
def solution(n: int, k: int, s: str) -> str:
    # write code here
    s_list = list(s)
    swap_count = 1
    for i in range(n):
        # 当前字符为0,且不是第一个
        if s_list[i] == '0' and i != 0:
            # 和前一个交换
            s_list[i], s_list[i - 1] = s_list[i - 1], s_list[i]
            swap_count += 1
            if swap_count > k:
                break
    return "".join(s_list)

print(solution(7, 3, "1101001"))输出结果是1010011,不能一次从左往右遍历,可能有其他情况字典序更小

3.2修改贪心策略

我们每次都选择当前位置及其右侧的最小字符,并将其尽可能地向左移动,直到达到 k 次交换的限制。这样可以确保在有限的交换次数内,得到字典序最小的字符串。

image.png

def solution(n: int, k: int, s: str) -> str:
    # write code here
    s_list = list(s)
    swap_count = 0
    for i in range(n):
        # 找出当前字符后最小的字符
        min_index = i
        for j in range(i + 1, n):
            if s_list[j] < s_list[min_index]:
                min_index = j
        # 尽可能往前移
        while min_index > i and swap_count < k:
            s_list[min_index], s_list[min_index - 1] = s_list[min_index - 1], s_list[min_index]
            min_index -= 1
            swap_count += 1

        # 如果达到最大交换次数,break
        if swap_count >= k:
            break
    return "".join(s_list)

if __name__ == '__main__':
    print(solution(5, 2, "01010"))
    print(solution(7, 3, "1101001"))
    print(solution(5, 2, "01010") == '00101')
    print(solution(7, 3, "1101001") == '0110101')
    print(solution(4, 1, "1001") == '0101')