你想要解决力扣 761 题「特殊的二进制字符串」,核心需求是找到给定特殊二进制字符串能重排得到的最大字典序字符串。
问题背景与解题思路
首先明确特殊的二进制字符串定义:
解题核心思路(分治 + 贪心):
完整可运行代码
class Solution {
public String makeLargestSpecial(String s) {
// 递归终止条件:空字符串或长度为0,直接返回
if (s == null || s.length() == 0) {
return "";
}
// 存储拆分后的最小特殊二进制子串
List<String> parts = new ArrayList<>();
// 记录当前前缀中1的数量 – 0的数量(平衡值)
int balance = 0;
// 记录每个最小特殊子串的起始位置
int start = 0;
for (int i = 0; i < s.length(); i++) {
// 遇到1,平衡值+1;遇到0,平衡值-1
balance += s.charAt(i) == '1' ? 1 : –1;
// 当平衡值回到0时,说明找到了一个最小特殊子串 [start, i]
if (balance == 0) {
// 对该子串的内部(去掉首尾的1和0)递归处理,再拼接首尾
String sub = "1" + makeLargestSpecial(s.substring(start + 1, i)) + "0";
parts.add(sub);
// 更新下一个子串的起始位置
start = i + 1;
}
}
// 将拆分后的子串按字典序降序排列(贪心:大的子串放前面,整体字典序最大)
Collections.sort(parts, Collections.reverseOrder());
// 拼接所有排序后的子串,得到最终结果
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(part);
}
return sb.toString();
}
}
代码关键部分解释
平衡值(balance):
- 遍历字符串时,遇到 ‘1’ 加 1,遇到 ‘0’ 减 1;
- 当 balance == 0 时,说明从 start 到当前位置是一个最小特殊二进制子串(无法再拆分为更小的特殊子串)。
递归处理子串内部:
- 对于找到的最小子串 s[start..i],去掉首尾的 ‘1’ 和 ‘0’(即 s[start+1..i-1]),递归调用函数处理内部,保证内部也是最大字典序;
- 处理后再拼接回首尾的 ‘1’ 和 ‘0’,得到该子串的最大形式。
贪心排序:
- 将所有处理后的最小子串按字典序降序排列,拼接后整体字典序最大(例如 1100 比 1010 字典序大,应放在前面)。
示例验证
输入:s = "11011000"
执行过程:
总结
该解法时间复杂度主要由排序决定(假设拆分出 k 个子串,排序复杂度为 O(k log k)),空间复杂度为递归栈和存储子串的空间,是力扣该题的最优解法之一。





