目录
判断字符串排列能否相互打破 —— 题解与分析
题目描述
给定两个长度相等的字符串 s1 和 s2,判断是否存在 s1 的一个排列能“打破” s2 的一个排列,或者 s2 的一个排列能“打破” s1 的一个排列。
定义:
字符串 x 可以打破字符串 y(长度均为 n)当且仅当对于所有索引 i,满足 x[i] >= y[i] (基于字典序的字符比较)。
举个例子:
x = "abc"y = "aad"
因为 a >= a,b >= a,c >= d(不成立,c < d),所以 x 不能打破 y。
解题分析
这题的关键是理解“存在一个排列”意味着什么。排列指的是对字符串字符顺序的重新排列。我们不需要枚举所有排列,因为这会导致爆炸性复杂度(长度为 n 的字符串有 n! 种排列)。
重要观察
- 若存在排列
p1(基于s1)能打破p2(基于s2),那么我们可以让p1和p2都是各自字符串的“排序后的排列”(即字典序最小排列),因为排列的相对顺序对能否打破的判断最关键。 - 排序后,比较字符对应位置是否满足
p1[i] >= p2[i]即可判断。
换句话说,若排序后的 s1 的字符均大于或等于排序后的 s2 的对应字符,那么 s1 排列能打破 s2 排列。反之亦然。
解题方法
具体步骤
- 对字符串
s1和s2分别排序,得到arr1和arr2。 - 判断
arr1是否逐字符都大于等于arr2,若是,返回True。 - 判断
arr2是否逐字符都大于等于arr1,若是,返回True。 - 若上述两者都不满足,返回
False。
代码实现(Python)
class Solution:
def checkIfCanBreak(self, s1: str, s2: str) -> bool:
arr1 = sorted(s1)
arr2 = sorted(s2)
# 判断 s1 是否能打破 s2
s1_breaks_s2 = all(a >= b for a, b in zip(arr1, arr2))
# 判断 s2 是否能打破 s1
s2_breaks_s1 = all(a >= b for a, b in zip(arr2, arr1))
return s1_breaks_s2 or s2_breaks_s1
复杂度分析
- 时间复杂度:排序是 O(n log n),遍历比较是 O(n),整体时间复杂度为 O(n log n)。
- 空间复杂度:需要额外的空间存储排序结果,O(n)。
示例说明
假设:
s1 = "abc"
s2 = "xya"
sorted(s1)=['a', 'b', 'c']sorted(s2)=['a', 'x', 'y']
逐字符比较:
a >= a→ Trueb >= x→ False (b<x)c >= y→ False
所以 s1 不能打破 s2。
反向比较:
a >= a→ Truex >= b→ Truey >= c→ True
所以 s2 的排列可以打破 s1 的排列,返回 True。
其他示例
s1 = "abe"
s2 = "acd"
排序:
s1->['a','b','e']s2->['a','c','d']
比较 s1 是否能打破 s2:
a >= a→ Trueb >= c→ Falsee >= d→ True
比较 s2 是否能打破 s1:
a >= a→ Truec >= b→ Trued >= e→ False
两者均不满足,返回 False。
方法比较与总结
- 暴力枚举:枚举所有排列组合,判断是否存在满足条件的排列,时间复杂度极高,不可行。
- 排序法:对两个字符串排序,然后逐字符比较,时间复杂度 O(n log n),是最优解法。
排序法基于“存在排列能打破”的性质,巧妙地规避了全排列的爆炸性复杂度,简单高效。
总结
- 本题的难点在于理解“存在一个排列能打破另一个排列”的定义。
- 通过对两个字符串排序,判断是否存在单调递增关系即可确定结果。
- 代码简洁,时间效率高,是解决该问题的标准范式。

被折叠的 条评论
为什么被折叠?



