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

71 阅读4分钟

首先来简单看一下题目

image.png

简单思考一下思路

要解决这个问题,我们需要通过有限次的相邻字符交换,在二进制字符串中实现字典序最小化。为了实现这一点,我们可以采用贪心的策略,从左到右扫描字符串,尝试将每一个 0 尽量向前移动。

以下是解决思路的分析:

解题思路

  1. 遍历字符串:从左到右遍历字符串中的每个字符。
  2. 寻找 0:对于当前字符如果是 1,则检查后面的字符,找到下一个 0。
  3. 计算移动:根据当前 1 的索引和 0 的索引计算需要移动的步数。如果需要的步数小于等于 k,则可以交换这个 0 到当前位置。
  4. 交换:进行必要的交换,并更新 k 的值。
  5. 重复过程:继续遍历直到 k 用完或字符串遍历结束。
  6. 输出结果:最后输出经过操作后的字符串。

算法步骤

  1. 初始化 result 字符串为原始字符串。

  2. 从左到右遍历字符串:

    • 如果当前字符是 1:

      • 查找后面能找到的 0,直到使用的操作次数 k 用完或者找到所有的 0。
      • 对找到的 0 进行相应的交换到当前字符位置。
  3. 继续此过程,直到遍历完成。

  4. 返回修改后的字符串。

下来展示代码

```#include <iostream>
#include <vector>
#include <string>

using namespace std;

string moved(string s) {
    for (int i = 0,I=s.size(); i < I-1; i++) {
        int j=i+1;
        if (s[i] == '0')continue;
        if(s[i]=='1'&&s[j]=='1')continue;
        else if (s[i] == '1' && s[j] == '0') {
            swap(s[i], s[j]);
            return s;
        }
    }
    return s;
}

string solution(int n, int k, string s) {
    vector<string>dp(k+1);
    dp[0] = s;
    for (int i = 1; i <= k; i++) {
        string t = dp[i - 1];
        dp[i] = moved(t);
    }
    return dp[k];
}

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. 思维的灵活性:在遇到字符串相关的问题时,我们需要迅速确定能够操作的范围和限制。此类问题往往要求在给定条件下进行最佳选择,锻炼我们在动态变化中的决策能力。
  2. 贪心策略的有效性:贪心算法通常能够在许多情况下提供有效的解决方案。这种方法通常适合于那些可以通过局部最优解逐步逼近全局最优解的问题。在此题中,我们每次通过移动 0 来尝试达成更小的字典序,符合贪心的思路。
  3. 细节的把控:实现过程中的细节非常重要,比如如何高效地找到可以交换的字符、如何计算移动所需的步骤等。好的细节把控能够避免不必要的复杂度和出错。
  4. 练习的重要性:通过不断地练习类似的题型,有助于提高应对复杂问题的能力。尤其是在面临时间限制的情况下,能够迅速找到解决方案是非常关键的。

类似题目的思路

  1. 确定操作范围:首先明白在具体的约束下(如最多的操作次数),哪些字符是可以被交换的 (如相邻字符), 并根据这些限制来制定策略。
  2. 优先处理:总是优先考虑对整体结果影响最大的操作,比如优先将 0 移动到前面,以最小化字符串的字典序。
  3. 记录状态:如果问题较为复杂,可以考虑使用额外的数组或数据结构来记录已经交换过的字符及其位置,以便快速查找和操作。
  4. 考虑极端情况:常常忽视一些边界情况,如字符串已经是字典序最小或操作次数不足以进行任何有效交换等。这些情况都要在设计算法时加以考虑。

总之,通过不断的练习和总结,我们不仅能够提高解题能力,还能更深入地理解算法的原理和应用场景。对于字符串和数组类的问题,灵活运用贪心和动态规划思路,将帮助我们在编程竞赛或技术面试中更加自信地解决问题。