给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
(让人抓狂的一道题目∑(っ°Д°;)っ)
思路
如果要使得两相邻的字符不同,那么出现次数最多的那个数的数量必须满足下面条件,如下图所示,比如下面的a是出现次数最多的
这个时候a的数量已经达到了临界值,如果再多一个 a ,那么至少有两个 a 是相邻的。所以这里出现次数最多的那个字符数量的临界值是threshold = (length + 1) >> 1(其中 length 是字符串的长度)
如果能使得两相邻的字符不同,我们可以先把出现次数最多的那个字符放到新字符串下标为偶数的位置上,放完之后在用其他的字符填充字符串剩下的位置。
注意这里能不能先把出现次数最多的字符放到字符串下标为奇数的位置呢,当然是不可以的。比如我们上面举的例子abacaba本来是可以满足的,如果放到下标为奇数的位置,最后一个 a 就没法放了,除非放到最前面,那又变成了放到下标为偶数的位置了。
思路来源:
作者:sdwwld
链接:https://leetcode-cn.com/problems/reorganize-string/solution/javadai-ma-ji-bai-liao-100de-yong-hu-by-sdwwld/
然后!!!代码:
首先是
错误代码
import java.util.Scanner;
class Solution {
public String reorganizeString(String S) {
int len=S.length();
int []eng=new int[26];
char []c_str=S.toCharArray();
int max_num=0;
int tmp_num=1;
char tmp_c=0;
eng[c_str[0]-'a']++;
for(int i=1;i<len;i++){
eng[c_str[i]-'a']++;
if(c_str[i]==c_str[i-1]){
tmp_num++;
}
else if(max_num<tmp_num){
max_num=tmp_num;
tmp_c=c_str[i-1];
tmp_num=0;
}
}
if(max_num>(len+1)/2){
return "";
}
int index=0;
for(int i=0;i<max_num;i++){
c_str[index]=tmp_c;
eng[tmp_c-'a']--;
index+=2;
}
for(int i=0;i<26;i++){
while(eng[i]>0){
if(index>=len){
index=1;
}
c_str[index]=(char)(i+'a');
index+=2;
eng[i]--;
}
}
return new String(c_str);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s=scan.next();
Solution so=new Solution();
String res=so.reorganizeString(s);
System.out.print(res);
}
}
这个错误代码总体思路与上面的思路来源一致,只是中间对如何获得数量最多的字符这里有点改动,原来的想法是利用一次遍历记录下来最大值以及相应字符,但是这种思路错在只适合相同字母连续出现的情况,否则就出错。(因为第一次遍历判断条件为:后一个字母是否与前一个字母相同,这种思路显然是有缺陷的)
正确代码
class Solution {
public String reorganizeString(String S) {
int len=S.length();
int []eng=new int[26];
char []c_str=S.toCharArray();
int max_num=0;
char tmp_c=0;
for(int i=0;i<len;i++){
eng[c_str[i]-'a']++;
}
for(int i=0;i<26;i++){
if(max_num<eng[i]){
max_num=eng[i];
tmp_c=(char)(i+'a');
}
}
if(max_num>(len+1)/2){
return "";
}
int index=0;
for(int i=0;i<max_num;i++){
c_str[index]=tmp_c;
eng[tmp_c-'a']--;
index+=2;
}
for(int i=0;i<26;i++){
while(eng[i]-->0){
if(index>=len){
index=1;
}
c_str[index]=(char)(i+'a');
index+=2;
}
}
return new String(c_str);
}
}
另外,很容易出错的地方在于
1、int转换为char字符时候需要强制类型转换!写法必须把int的所有都放在括号中
2、对这种“水桶”类的思路,注意在将int转换为char时候,是用i+‘a’,而不是数组值c[i]+‘a’;
3、同样对于此类水桶类的方法,需要注意遍历时次数为26,不是len!