携手创作,共同成长!这是我参与「掘金日新计划 · 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();
}
}
提交排名
思路很简单,用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';
}
}
提交排名
这个算法首先是循环遍历一遍,数出字母和数组的个数,如果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,前进的道路还很远啊!!!