您的位置:首页 > 健康 > 美食 > 排序题目:检查一个字符串是否可以打破另一个字符串

排序题目:检查一个字符串是否可以打破另一个字符串

2024/10/6 10:32:50 来源:https://blog.csdn.net/stormsunshine/article/details/125547723  浏览:    关键词:排序题目:检查一个字符串是否可以打破另一个字符串

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 证明
    • 代码
    • 复杂度分析

题目

标题和出处

标题:检查一个字符串是否可以打破另一个字符串

出处:1433. 检查一个字符串是否可以打破另一个字符串

难度

4 级

题目描述

要求

给定两个长度相等的字符串 s1 \texttt{s1} s1 s2 \texttt{s2} s2,检查是否存在一个 s1 \texttt{s1} s1 的排列可以打破 s2 \texttt{s2} s2 的一个排列,或者是否存在一个 s2 \texttt{s2} s2 的排列可以打破 s1 \texttt{s1} s1 的一个排列。

字符串 x \texttt{x} x 可以打破字符串 y \texttt{y} y(两者长度都为 n \texttt{n} n)需满足对于所有 0 ≤ i < n \texttt{0} \le \texttt{i} < \texttt{n} 0i<n 都有 x[i] ≥ y[i] \texttt{x[i]} \ge \texttt{y[i]} x[i]y[i](字典序意义下的顺序)。

示例

示例 1:

输入: s1 = "abc", s2 = "xya" \texttt{s1 = "abc", s2 = "xya"} s1 = "abc", s2 = "xya"
输出: true \texttt{true} true
解释: "ayx" \texttt{"ayx"} "ayx" s2="xya" \texttt{s2="xya"} s2="xya" 的一个排列, "abc" \texttt{"abc"} "abc" 是字符串 s1="abc" \texttt{s1="abc"} s1="abc" 的一个排列,且 "ayx" \texttt{"ayx"} "ayx" 可以打破 "abc" \texttt{"abc"} "abc"

示例 2:

输入: s1 = "abe", s2 = "acd" \texttt{s1 = "abe", s2 = "acd"} s1 = "abe", s2 = "acd"
输出: false \texttt{false} false
解释: s1="abe" \texttt{s1="abe"} s1="abe" 的所有排列包括: "abe" \texttt{"abe"} "abe" "aeb" \texttt{"aeb"} "aeb" "bae" \texttt{"bae"} "bae" "bea" \texttt{"bea"} "bea" "eab" \texttt{"eab"} "eab" "eba" \texttt{"eba"} "eba" s2="acd" \texttt{s2="acd"} s2="acd" 的所有排列包括: "acd" \texttt{"acd"} "acd" "adc" \texttt{"adc"} "adc" "cad" \texttt{"cad"} "cad" "cda" \texttt{"cda"} "cda" "dac" \texttt{"dac"} "dac" "dca" \texttt{"dca"} "dca"。然而没有任何 s1 \texttt{s1} s1 的排列可以打破 s2 \texttt{s2} s2 的排列。也没有任何 s2 \texttt{s2} s2 的排列能打破 s1 \texttt{s1} s1 的排列。

示例 3:

输入: s1 = "leetcodee", s2 = "interview" \texttt{s1 = "leetcodee", s2 = "interview"} s1 = "leetcodee", s2 = "interview"
输出: true \texttt{true} true

数据范围

  • s1.length = n \texttt{s1.length} = \texttt{n} s1.length=n
  • s2.length = n \texttt{s2.length} = \texttt{n} s2.length=n
  • 1 ≤ n ≤ 10 5 \texttt{1} \le \texttt{n} \le \texttt{10}^\texttt{5} 1n105
  • 所有字符串都只包含小写英语字母

解法

思路和算法

对于长度为 n n n 的两个字符串 s 1 s_1 s1 s 2 s_2 s2,假设存在 s 1 s_1 s1 s 2 s_2 s2 的排列使得 s 1 s_1 s1 的排列可以打破 s 2 s_2 s2 的排列或者 s 2 s_2 s2 的排列可以打破 s 1 s_1 s1 的排列,则将字符串 s 1 s_1 s1 s 2 s_2 s2 分别升序排序之后得到的两个排列之间一定存在打破的关系。

将字符串 s 1 s_1 s1 s 2 s_2 s2 分别升序排序,用 t 1 t_1 t1 t 2 t_2 t2 分别表示 s 1 s_1 s1 s 2 s_2 s2 升序排序之后的结果。排序之后,对于每个 0 ≤ i < n 0 \le i < n 0i<n,比较 t 1 [ i ] t_1[i] t1[i] t 2 [ i ] t_2[i] t2[i] 的大小,并判断可能的打破关系。

  • 如果 t 1 [ i ] = t 2 [ i ] t_1[i] = t_2[i] t1[i]=t2[i],则根据下标 i i i 处的字母判断,可能是 t 1 t_1 t1 打破 t 2 t_2 t2 或者 t 2 t_2 t2 打破 t 1 t_1 t1

  • 如果 t 1 [ i ] > t 2 [ i ] t_1[i] > t_2[i] t1[i]>t2[i],则根据下标 i i i 处的字母判断,只可能是 t 1 t_1 t1 打破 t 2 t_2 t2

  • 如果 t 1 [ i ] < t 2 [ i ] t_1[i] < t_2[i] t1[i]<t2[i],则根据下标 i i i 处的字母判断,只可能是 t 2 t_2 t2 打破 t 1 t_1 t1

因此如果存在两个不同的下标 j j j k k k 使得 t 1 [ j ] > t 2 [ j ] t_1[j] > t_2[j] t1[j]>t2[j] t 1 [ k ] < t 2 [ k ] t_1[k] < t_2[k] t1[k]<t2[k],则不存在 s 1 s_1 s1 s 2 s_2 s2 的排列使得一个字符串的排列可以打破另一个字符串的排列。

将字符串 s 1 s_1 s1 s 2 s_2 s2 升序排序之后,判断两个字符串的排列是否存在打破关系的方法是:同时遍历两个排序后的字符串 t 1 t_1 t1 t 2 t_2 t2,统计 t 1 t_1 t1 的字符大于 t 2 t_2 t2 的字符的下标个数 greater \textit{greater} greater 以及 t 1 t_1 t1 的字符小于 t 2 t_2 t2 的字符的下标个数 less \textit{less} less。遍历结束之后,根据 greater \textit{greater} greater less \textit{less} less 的值判断两个字符串的排列是否存在打破关系。

  • 如果 greater \textit{greater} greater less \textit{less} less 中至少有一个为 0 0 0,则两个字符串的排列存在打破关系。

  • 如果 greater \textit{greater} greater less \textit{less} less 都大于 0 0 0,则两个字符串的排列不存在打破关系。

实现方面,由于 Java 中的 String \texttt{String} String 类型的对象是不可变的,因此需要对 s 1 s_1 s1 s 2 s_2 s2 分别调用 toCharArray \texttt{toCharArray} toCharArray 方法得到 char \texttt{char} char 类型的数组,然后对两个字符数组排序。

证明

将字符串 s 1 s_1 s1 s 2 s_2 s2 分别升序排序之后,如果两个有序字符串之间存在打破关系,由于两个有序字符串分别是 s 1 s_1 s1 s 2 s_2 s2 的排列,因此存在 s 1 s_1 s1 s 2 s_2 s2 使得打破关系成立。

如果两个有序字符串之间不存在打破关系,则两个字符串的任意排列之间都不存在打破关系。证明如下。

如果两个有序字符串之间不存在打破关系,则存在两个不同的下标 j j j k k k 使得 t 1 [ j ] > t 2 [ j ] t_1[j] > t_2[j] t1[j]>t2[j] t 1 [ k ] < t 2 [ k ] t_1[k] < t_2[k] t1[k]<t2[k]。以下考虑 j < k j < k j<k 的情况,使用相同的思路也可以证明 j > k j > k j>k 的情况。

  • 假设存在大于 k k k 的下标 k ′ k' k 使得 t 1 [ k ′ ] ≥ t 2 [ k ] t_1[k'] \ge t_2[k] t1[k]t2[k],将 t 1 [ k ] t_1[k] t1[k] t 1 [ k ′ ] t_1[k'] t1[k] 的两个字符交换之后有 t 1 [ k ] ≥ t 2 [ k ] t_1[k] \ge t_2[k] t1[k]t2[k]在交换 t 1 t_1 t1 的两个字符之后,一定有 t 1 [ k ′ ] < t 2 [ k ′ ] t_1[k'] < t_2[k'] t1[k]<t2[k],由于 t 2 [ k ′ ] ≥ t 2 [ k ] t_2[k'] \ge t_2[k] t2[k]t2[k]。因此 t 1 t_1 t1 的最大的 n − k n - k nk 个字符不可能同时大于等于 t 2 t_2 t2 的最大的 n − k n - k nk 个字符(对应下标)。

  • 假设存在小于 j j j 的下标 j ′ j' j 使得 t 1 [ j ′ ] ≤ t 2 [ j ] t_1[j'] \le t_2[j] t1[j]t2[j],将 t 1 [ j ] t_1[j] t1[j] t 1 [ j ′ ] t_1[j'] t1[j] 的两个字符交换之后有 t 1 [ j ] ≤ t 2 [ j ] t_1[j] \le t_2[j] t1[j]t2[j]在交换 t 1 t_1 t1 的两个字符之后,一定有 t 1 [ j ′ ] > t 2 [ j ′ ] t_1[j'] > t_2[j'] t1[j]>t2[j],由于 t 2 [ j ′ ] ≤ t 2 [ j ] t_2[j'] \le t_2[j] t2[j]t2[j]。因此 t 1 t_1 t1 的最小的 j + 1 j + 1 j+1 个字符不可能同时小于等于 t 2 t_2 t2 的最小的 j + 1 j + 1 j+1 个字符(对应下标)。

因此如果两个有序字符串之间不存在打破关系,则两个字符串的任意排列之间都不存在打破关系。

代码

class Solution {public boolean checkIfCanBreak(String s1, String s2) {int n = s1.length();char[] arr1 = s1.toCharArray();char[] arr2 = s2.toCharArray();Arrays.sort(arr1);Arrays.sort(arr2);int greater = 0, less = 0;for (int i = 0; i < n; i++) {if (arr1[i] > arr2[i]) {greater++;} else if (arr1[i] < arr2[i]) {less++;}}return greater == 0 || less == 0;}
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是字符串 s 1 s_1 s1 s 2 s_2 s2 的长度。需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间对两个字符数组排序,排序后需要 O ( n ) O(n) O(n) 的时间比较两个字符数组的相同位置字符,因此时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s 1 s_1 s1 s 2 s_2 s2 的长度。需要创建两个长度为 n n n 的字符数组,排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间,因此空间复杂度是 O ( n ) O(n) O(n)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com