[杨小白]_leetcode_1417. 重新格式化字符串

156 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

前言

小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标300题,记录从0到1的全过程!!

1417. 重新格式化字符串

2022年8月11号每日一题

1417. 重新格式化字符串

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

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

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

示例 1

输入:s = "a0b1c2"

输出:"0a1b2c"

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

示例 2

输入: s = "leetcode"

输出: ""

解释: "leetcode" 中只有字母,所以无法满足重新格式化的条件。

示例 3

输入: s = "1229857369"

输出: ""

解释: "1229857369" 中只有数字,所以无法满足重新格式化的条件。

示例 4

输入: s = "covid2019"

输出: "c2o0v1i9d"

示例 5

输入: s = "ab123"

输出: "1a2b3"

说明: 提示:

1 <= s.length <= 500

s 仅由小写英文字母和/或数字组成。

2.解法一,排序后,双指针组合

class Solution {
    public String reformat(String s) {
        StringBuilder sb=new StringBuilder();
        char[] str=s.toCharArray();
        int len=s.length();
        Arrays.sort(str);//排序
        for(int i=0,j=len-1;i<j;i++,j--){
            if(str[i]>'9'||str[j]<'a')//前半部分出现字母或后半部分出现数字
                return "";
            sb.append(str[i]);//数字
            sb.append(str[j]);//字母
        }
        if(len%2==1){//字符数为奇数,则要看数字多还是字母多
            if(str[len/2]>'9')//中间字符是字母
                sb.insert(0,str[len/2]);//字母多,插到字符串首
            else     
                sb.append(str[len/2]);//数字多,插到字符串末尾
        }
    return sb.toString();
    }
}

提交排名

image.png

思路很简单,用sort排序之后,用一个StringBuffer接收,左右指针分别从前后遍历,如果发现异常就直接报错,如果最后能遍历完,说明可以返回符合要求的字符串,并且已经存储在stringbuffer中了,tostring返回就可以了。

这个的时间复杂度,首先是排序平均是O(nlogn)然后遍历,这样就是O(nlogn + n),stringbuffer的添加忽略 空间复杂度,转为字符串O(n) stringbuffer,O(n)所以空间复杂度是O(2n)

解法二, 遍历数出数字和字母个数,左右指针遍历

class Solution {
    public String reformat(String s) {
        int numOfNum = 0;
        int numOfCode = 0;
        char[] chars = s.toCharArray();
        for(int i =0; i< chars.length; i++) {
            if(chars[i]>='0'&&chars[i]<='9') {
                numOfNum++;
            } else {
                numOfCode++;
            }
        }
        if(Math.abs(numOfCode-numOfNum)>1) {
            return "";
        }
        boolean keyl = numOfNum > numOfCode; //true 起点就是num  false 起点就是code
        boolean keyr = numOfCode > numOfNum; //true 终点就是code false 终点就算num
        int l = 0;
        int r = chars.length - 1;
        while(l < r) {
            while(l < r && isNum(chars[l])==keyl) {
                keyl = !keyl;
                l++;
            }
            while(l < r && isCode(chars[r])==keyr) {
                keyr = !keyr;
                r--;
            }
            swap(chars,l,r);
        }
        return new String(chars);
    }
    public void swap(char[] chars, int l, int r) {
        char t = chars[l];
        chars[l] = chars[r];
        chars[r] = t;
    }
    public boolean isNum(char c) {
        return c>='0'&&c<='9';
    }
    public boolean isCode(char c) {
        return c>='a'&&c<='z';
    }
}

提交排名

image.png

这个算法首先是循环遍历一遍,数出字母和数组的个数,如果Math.abs(numOfCode-numOfNum)>1,那就不可能按照题目要求排序,直接返回空字符串即可。

如果能按照要求排序,那就有两种可能,numOfCode=numOfNum,或者numOfCode、numOfNum相差1。

这里我们引进了 boolean类型的 keyl和keyr,通过判断numOfCode、numOfNum大小给他们赋初值,使得:

keyl = true 是左指针就需要是一个num的值,key1 = false的时候说明左指针就要是code的值

keyr = false 是右指针就需要是一个code的值,keyr = true的时候说明左指针就要是num的值

左右指针循环遍历,从左找到不符合要求的,从右找到不符合要求的,交换位置。有点类似于快排,大家仔细一看就能明白了。

时间复杂度,第一遍遍历计算数字和字符的数量O(n),第二遍左右指针也是O(n),所以时间复制度是O(2n)。 空间复杂度,字符串数字O(n)和指针等值O(1),所以空间复杂度O(n)。

解析

这个题也算不上一个普通的简单题把,应该算是应该略简单的中等难度的题了。

3.结束

每日一题每日一题,gogogo,前进的道路还很远啊!!!