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

92 阅读4分钟

算法分析:最小字典序字符串问题

问题背景

小U拥有一个由 01 组成的字符串,她可以进行最多 k 次操作,每次操作允许交换相邻的两个字符。任务目标是通过这些操作,使字符串的字典序最小。字典序可以看作是字符串按字典排列的顺序,越靠前的字符串字典序越小。

示例:

  • 输入字符串为 01010,操作次数 k = 2
  • 最优解:通过两次操作可以得到 00101,这是不超过 2 次交换后字典序最小的字符串。

该问题的关键是如何在有限次数的交换中,通过局部优化将 0 尽可能地移到字符串的前面,而不影响后续操作的可能性。


分析与思路

基础思路

  1. 局部最优解法
    从左到右扫描字符串,优先尝试将每个 0 移到当前可能的最靠前位置。由于每次交换仅限于相邻字符,0 能够移动的范围受到操作次数 k 的限制。因此,问题可以分解为多次局部最优选择。

  2. 贪心策略
    在每一步操作中,尝试找到离当前位置最近的 0,将其移到当前位置,同时减少对应消耗的操作次数。这种贪心策略保证了每一步都为当前局部字典序最小。


算法设计

为了实现上述思路,设计如下步骤:

  1. 扫描字符串:从左到右依次检查每个字符:

    • 如果当前字符是 1,继续扫描以寻找可以移动到该位置的 0
    • 使用双指针或区间扫描快速找到当前能移动的最靠近的 0
  2. 交换字符:将 0 与其前方所有的 1 相邻交换,直到它到达目标位置,或操作次数用尽。

  3. 更新剩余操作次数:每次移动都消耗一定的操作次数 k,如果 k 减少到 0,则终止操作。


时间与空间复杂度分析

  1. 时间复杂度

    • 最坏情况下,每个字符都需要扫描 k 次,其时间复杂度为 O(n*k)
    • 在实践中,由于 k 的限制,算法通常可以在少于 O(n*k) 的时间内完成。
  2. 空间复杂度

    • 只需要常量级额外空间存储索引和计数变量,空间复杂度为 O(1)

算法实现

以下是基于贪心策略的 C++ 实现:

#include <iostream>
#include <string>
using namespace std;

string solution(int n, int k, string s) {
    if (k == 0) return s; // 如果没有可用操作,直接返回原字符串

    for (int i = 0; i < n; i++) {
        if (s[i] == '1') {
            int minZeroIndex = -1;
            // 在当前位置右边范围内寻找最靠近的 0
            for (int j = i + 1; j < n && j <= i + k; j++) {
                if (s[j] == '0') {
                    minZeroIndex = j;
                    break;
                }
            }

            if (minZeroIndex != -1) {
                // 计算移动代价并更新剩余操作次数
                k -= minZeroIndex - i;

                // 将 0 移动到当前位置
                swap(s[i], s[minZeroIndex]);
            }
        }
    }

    return s;
}

int main() {
    cout << (solution(5, 2, "01010") == "00101") << endl;
    cout << (solution(7, 3, "1101001") == "0110101") << endl;
    cout << (solution(4, 1, "1001") == "0101") << endl;
    return 0;
}

测试与验证

运行以上代码后,结果如下:


1
1
1

说明算法在测试用例中的表现符合预期。


算法优化分析

优化潜力

  1. 提前终止条件
    k = 0 时,无需继续扫描和交换,可以直接返回结果。
  2. 减少扫描范围
    可以通过索引记录上一次交换的位置,避免重复扫描同一区域。
  3. 其他数据结构的引入
    使用堆或队列来优化寻找最近的 0,可以进一步降低局部扫描的代价。

应用场景拓展

  • 字符排序:此算法思想可应用于其他字符集合,解决“最优调整”问题。
  • 滑动窗口问题:通过限制区间操作次数,类似算法可以解决范围优化问题。

总结与思考

通过分析发现,本问题的核心在于如何在有限的资源(操作次数)中,找到局部最优解并递推至全局最优解。这种贪心策略的应用,既保证了算法的效率,也降低了实现的复杂度。

此外,问题还蕴含了许多优化的可能性,例如使用更高效的数据结构或提前终止条件。对于类似问题,解题过程中应注重数学特性和问题模型的本质分析,从而设计出更为优雅的算法。