• 【字符串】重新格式化字符串


    题目描述

    给你一个混合了数字和字母的字符串 s,其中的字母均为小写英文字母。

    请你将该字符串重新格式化,使得任意两个相邻字符的类型都不同。也就是说,字母后面应该跟着数字,而数字后面应该跟着字母。

    请你返回 重新格式化后 的字符串;如果无法按要求重新格式化,则返回一个 空字符串 。

    示例 1:

    输入:s = "a0b1c2"
    输出:"0a1b2c"
    解释:"0a1b2c" 中任意两个相邻字符的类型都不同。 "a0b1c2", "0a1b2c", "0c2a1b" 也是满足题目要求的答案。

    解题思路

    这道题实际就是字段串处理的题目,基本思路如下:

    1. 对字符串内的字符进行分类,分成数字和字符,分别放到2个List中;
    2. 比较2个List的长度,如果2个List的长度相差大于等于2,那么直接返回空字符串;
    3. 如果2个List的长度相差小于2,则对结果进行merge;

    代码实现

    1. import java.util.ArrayList;
    2. import java.util.List;
    3. class Solution2 {
    4. public String reformat(String s) {
    5. List l1 = new ArrayList<>(s.length());
    6. List l2 = new ArrayList<>(s.length());
    7. for (char c : s.toCharArray()) {
    8. if (Character.isDigit(c)) {
    9. l1.add(c);
    10. } else {
    11. l2.add(c);
    12. }
    13. }
    14. if (l1.size() > l2.size()) {
    15. return merge(l1, l2);
    16. } else {
    17. return merge(l2, l1);
    18. }
    19. }
    20. private String merge(List l1, List l2) {
    21. if (l1.size() - l2.size() >= 2) {
    22. return "";
    23. }
    24. char[] chars = new char[l1.size() + l2.size()];
    25. int i1 = 0;
    26. int i2 = 0;
    27. int i = 0;
    28. while (i1 < l1.size() && i2 < l2.size()) {
    29. chars[i++] = l1.get(i1++);
    30. chars[i++] = l2.get(i2++);
    31. }
    32. if (i1 < l1.size()) {
    33. chars[i++] = l1.get(i1++);
    34. }
    35. return new String(chars);
    36. }
    37. }

    代码优化

    上述代码在耗时方面不是最优的,为了能优化耗时,进行如下改造:

    1. 提供一个变量c1统计字符串出现的次数;
    2. 用数组的长度减去c1,获得非数字的长度,记录为c2;
    3. 如果c2 - c1 的绝对值大于等于2,直接返回空字符串;
    4. 如果c2 - c1 的绝对值小于2,则对字符数组进行merge;

    字符数组merge逻辑如下:

    1. 如果数字字符更多,则数字字符从0开始计算,非数字字符从1开始计算;否则数字字符从1开始计算,非数字字符从0开始计算
    2. 接着遍历数组,设置每个字符对应的下标值;
    3. 最后返回结果。

    按照上述思路代码实现如下:

    1. class Solution {
    2. public String reformat(String s) {
    3. int c1 = 0;
    4. char[] array = s.toCharArray();
    5. for (char c : array) {
    6. if (isDigit(c)) {
    7. c1++;
    8. }
    9. }
    10. int c2 = array.length - c1;
    11. return merge(c1, c2, array);
    12. }
    13. boolean isDigit(char c) {
    14. return c >= '0' && c <= '9';
    15. }
    16. private String merge(int c1, int c2, char[] array) {
    17. if (c1 - c2 >= 2 || c1 - c2 <= -2) {
    18. return "";
    19. }
    20. if (c1 > c2) {
    21. c1 = 0;
    22. c2 = 1;
    23. } else {
    24. c1 = 1;
    25. c2 = 0;
    26. }
    27. char[] res = new char[array.length];
    28. for (char c : array) {
    29. if (isDigit(c)) {
    30. res[c1] = c;
    31. c1 += 2;
    32. } else {
    33. res[c2] = c;
    34. c2 += 2;
    35. }
    36. }
    37. return new String(res);
    38. }
    39. }

    总结 

    这道题整体就是字符串的解析和判定,为了提升执行效率,我把临时存储2种类型的List给取消了,在字符合并时也做了优化,最终达到最优的耗时。当然,如果有更加好、更加高效的思路,欢迎回复。

  • 相关阅读:
    Git拉取指定文件或者文件夹
    向日葵远程分辨率过低解决办法
    学习Golang时遇到的似懂非懂的概念
    Fashion MNIST与分类算法
    【遍历二叉树的非递归算法,二叉树的层次遍历】
    Centos 安装MySQL 5.7.38
    23种设计模式(十五)解释器模式(阁瑞钛伦特软件-九耶实训)
    vscode开发STM32(四)--- 技巧篇
    3-4数据链路层-局域网
    计算机网络两位伟人
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126295828