在学习编程的过程中,我喜欢独自钻研算法题,每一次攻克难题后的成就感总是让我兴奋不已。最近,在使用 豆包MarsCode 刷题时,遇到了一道让我印象深刻的题目:通过有限次相邻交换,使一个由 0 和 1 组成的字符串的字典序尽可能小。这次经历让我不仅提升了编程能力,还对算法设计有了更深的体会。
问题描述
题目的规则很简单:
- 给定一个只包含
0和1的字符串。 - 可以最多进行
k次相邻字符的交换操作。 - 目标是通过这些交换,使最终的字符串的字典序尽可能小。
看似是一个简单的贪心算法题,但当我深入思考时,发现这题并没有想象中那么容易解决。
初次尝试:简单的贪心算法
在看到题目后,我的第一反应是:找到所有的 0,尽可能地把它们移动到字符串的左侧不就可以了吗?于是,我快速写下了第一版代码:
public static String solution(int n, int k, String s) {
char[] chars = s.toCharArray();
for (int i = 0; i < n; i++) {
if (chars[i] == '0') {
int pos = i;
while (pos > 0 && chars[pos - 1] == '1' && k > 0) {
chars[pos] = '1';
chars[pos - 1] = '0';
pos--;
k--;
}
}
}
return new String(chars);
}
在简单测试了一些输入后,我发现代码能够跑通基本的样例,例如:
- 输入
n=5, k=2, s="01010",输出为00101。 - 输入
n=7, k=3, s="1101001",输出为0110101。
然而,当我尝试更复杂的测试用例时,结果并不正确。这让我意识到,简单的贪心算法并不足以覆盖所有情况。
深入分析问题
为了进一步优化解法,我借助了 豆包MarsCode。我把题目描述和代码输入到 MarsCode 中,并向它提问:“这个问题有什么潜在的边界条件?” MarsCode 很快给出了答案:
- 如果
k次数不够,将0移到最左边后可能不是最优解。 - 如果不仔细规划移动顺序,可能会浪费
k,导致结果次优。 - 需要在移动过程中动态调整剩余的
k,并在不同位置间权衡。
通过 MarsCode 的提示,我意识到,这题的核心不只是“尽量左移 0”,还要考虑交换次数 k 的合理分配。我进一步优化了算法。
最终解法
根据 MarsCode 的建议,我对代码进行了优化,在每次交换后动态更新剩余次数 k 并提前停止:
public static String solution(int n, int k, String s) {
char[] chars = s.toCharArray();
for (int i = 0; i < n; i++) {
if (chars[i] == '0') {
int pos = i;
while (pos > 0 && chars[pos - 1] == '1' && k > 0) {
chars[pos] = '1';
chars[pos - 1] = '0';
pos--;
k--;
// 如果没有剩余交换次数,提前退出
if (k == 0) {
break;
}
}
}
// 如果没有剩余交换次数,提前退出外层循环
if (k == 0) {
break;
}
}
return new String(chars);
}
这次代码更加高效,并能够通过所有测试用例。特别是在一些边界条件下,例如:
- 输入
n=5, k=1, s="10001",输出应为01001。 - 输入
n=10, k=4, s="1101101100",输出应为0110110110。
最终收获
当我看到代码顺利通过所有测试时,内心充满了成就感。这次刷题的经历让我感受到 AI 的强大力量,尤其是 MarsCode 不仅能给出答案,还能帮助我发现问题背后的细节,让我从错误中学习并优化解法。
这道题目表面上是一个简单的字符串处理问题,但实际上它考验了对贪心策略的掌控能力和对边界条件的考虑。我深深感受到,在编程学习中,思考和分析问题的过程才是最重要的,而 AI 工具是帮助我提升的最佳助手。
从那以后,每当我遇到复杂问题,我都会尝试和 MarsCode 一起解决,它不仅是工具,更像是一个耐心的“学习伙伴”,让我在一次次攻克难题后不断成长!