如何在原字符串上分开大小写和数字?

手撕算法:输入一个字符串,里面有大写字母、小写字母、数字,处理结束后,大写字母在前,然后是小写字母,最后是数字,要求:在原有字符串上做交换实现,不要建新的数据结构。

1 个回答

  • 水月大师
    遇见错的人会消耗你,遇见对的人会治愈你。
    ## 这是不是 LeetCode 原题? **不是**一题同样表述的原题。它最接近的思路是 **LeetCode 75:Sort Colors**(荷兰国旗三路划分,原地三分区),也可类比 **LeetCode 905:Sort Array by Parity**(原地二分区)。本题就是把字符按三类(大写/小写/数字)做**原地三路分区**。 ## 解法(来源于 LC75 的三指针/荷兰国旗法) 把每个字符映射到类别: * 大写 → 0 * 小写 → 1 * 数字 → 2 用三指针在 **一个 pass** 内原地划分为「0 区 | 1 区 | 2 区」: * `lo` 指向 0 区的下一个待放位置; * `mid` 当前扫描指针; * `hi` 指向 2 区的下一个待放位置(从右往左缩)。 规则: * 类别=0:`swap(mid, lo)`;`mid++`, `lo++` * 类别=1:`mid++` * 类别=2:`swap(mid, hi)`;`hi--`(注意这里 **mid 不动**,因为换过来的新字符还未分类) > 复杂度:时间 `O(n)`,额外空间 `O(1)`(就地交换)。 > 说明:题目只要求分区,不要求稳定性(分区内相对顺序可能改变)。 > 语言注意:Java/String 不可变,需先转 `char[]` 再原地交换;这在算法意义上等价于对“可写字符数组”原地操作。 ### Java 实现 ```java public class ReorderString { public static String reorder(String s) { char[] a = s.toCharArray(); // Java 字符串不可变,只能在 char[] 上原地换 int n = a.length; int lo = 0, mid = 0, hi = n - 1; while (mid <= hi) { int t = cat(a[mid]); if (t == 0) { // 大写 swap(a, lo++, mid++); } else if (t == 1) { // 小写 mid++; } else { // 数字 swap(a, mid, hi--); } } return new String(a); } private static int cat(char c) { if (Character.isUpperCase(c)) return 0; if (Character.isLowerCase(c)) return 1; // 题意给定只含大/小写与数字;若有杂项,这里可按需定义为 2 或直接返回 2 return 2; // 数字 } private static void swap(char[] a, int i, int j) { char tmp = a[i]; a[i] = a[j]; a[j] = tmp; } public static void main(String[] args) { System.out.println(reorder("aB3cD1eF2")); // 可能输出: BDFace312(分区正确,分区内不保证稳定) } } ``` ### 可选:两次分区的写法(也是原地,思路类似 LC905→二分 + 再二分) 1. 先把 **大写** 分到最前面; 2. 再对剩余段把 **小写** 分到前、**数字**到后。 同样 `O(n)` 两趟,`O(1)` 空间。 ### 小结 * 判断:**不是** LeetCode 原题;最接近 **LC75(三路原地分区)** 的思路。 * 实现:用 **三指针荷兰国旗法** 一次扫描原地分成「大写 | 小写 | 数字」。 * 性能:`O(n)`/`O(1)`;不保证分区内稳定顺序(题目也没要求)。
    发布于 2025-08-11 15:02 •IP属地 山西
    举报
    评论
    收藏