手把手教你玩转Codesys定时器:TON、TOF、TP、RTC功能块实战配置
2026/5/5 1:08:26
给定一个字符串s,检查是否能重新排列其中的字符,使得任意两个相邻的字符都不相同。
如果可以重新排列,返回任意一个满足条件的字符串。如果不能,返回空字符串""。
示例:
输入: s = "aab" 输出: "aba" 输入: s = "aaab" 输出: ""核心思想是优先处理出现频率最高的字符。
关键:
(n + 1) / 2(n为字符串长度),则无法重构方法:
importjava.util.*;classSolution{/** * 使用优先队列重构字符串,确保相邻字符不同 * * @param s 输入字符串 * @return 重构后的字符串,如果无法重构返回空字符串 */publicStringreorganizeString(Strings){// 1: 统计每个字符的频率int[]charCount=newint[26];for(charc:s.toCharArray()){charCount[c-'a']++;}// 2: 检查可行性 - 任何字符频率不能超过 (n+1)/2intn=s.length();for(intcount:charCount){if(count>(n+1)/2){return"";}}// 3: 构建最大堆,按频率排序// 堆中存储 [字符, 频率]PriorityQueue<int[]>maxHeap=newPriorityQueue<>((a,b)->b[1]-a[1]);for(inti=0;i<26;i++){if(charCount[i]>0){maxHeap.offer(newint[]{i,charCount[i]});}}// 4: 重构字符串StringBuilderresult=newStringBuilder();int[]prev=null;// 记录上一次使用的字符,避免连续使用while(!maxHeap.isEmpty()){// 取出频率最高的字符int[]current=maxHeap.poll();// 将字符添加到结果中result.append((char)('a'+current[0]));current[1]--;// 频率减1// 如果上一个字符还有剩余,重新放回堆中if(prev!=null&&prev[1]>0){maxHeap.offer(prev);}// 更新prev为当前字符prev=current;}// 如果结果长度等于原字符串长度,说明重构成功returnresult.length()==n?result.toString():"";}}classSolution{/** * 使用间隔放置策略重构字符串 * * @param s 输入字符串 * @return 重构后的字符串,如果无法重构返回空字符串 */publicStringreorganizeString(Strings){// 1: 统计字符频率int[]charCount=newint[26];intmaxFreq=0;charmaxChar=' ';for(charc:s.toCharArray()){charCount[c-'a']++;if(charCount[c-'a']>maxFreq){maxFreq=charCount[c-'a'];maxChar=c;}}// 2: 检查可行性intn=s.length();if(maxFreq>(n+1)/2){return"";}// 3: 创建结果字符数组char[]result=newchar[n];// 4: 先将最高频字符放在偶数位置 (0, 2, 4, ...)intindex=0;while(charCount[maxChar-'a']>0){result[index]=maxChar;index+=2;charCount[maxChar-'a']--;}// 5: 填充其他字符for(inti=0;i<26;i++){while(charCount[i]>0){// 如果偶数位置已满,切换到奇数位置if(index>=n){index=1;}result[index]=(char)('a'+i);index+=2;charCount[i]--;}}returnnewString(result);}}时间复杂度:
空间复杂度:
方法一(优先队列):
方法二(间隔放置):
publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:标准示例System.out.println("Test 1: \""+solution.reorganizeString("aab")+"\"");// "aba"// 测试用例2:无法重构System.out.println("Test 2: \""+solution.reorganizeString("aaab")+"\"");// ""// 测试用例3:单字符System.out.println("Test 3: \""+solution.reorganizeString("a")+"\"");// "a"// 测试用例4:两个不同字符System.out.println("Test 4: \""+solution.reorganizeString("ab")+"\"");// "ab" or "ba"// 测试用例5:复杂情况System.out.println("Test 5: \""+solution.reorganizeString("vvvlo")+"\"");// "vlvov"// 测试用例6:边界情况 - 最大频次刚好等于(n+1)/2System.out.println("Test 6: \""+solution.reorganizeString("aaaabc")+"\"");// 长度6,max=4,(6+1)/2=3,4>3 → ""// 测试用例7:长度为奇数的最大频次System.out.println("Test 7: \""+solution.reorganizeString("aaabc")+"\"");// 长度5,max=3,(5+1)/2=3 → 可以重构// 测试用例8:所有字符都不同System.out.println("Test 8: \""+solution.reorganizeString("abcdef")+"\"");// 原字符串即可// 测试用例9:空字符串System.out.println("Test 9: \""+solution.reorganizeString("")+"\"");// ""// 测试用例10:两个相同字符System.out.println("Test 10: \""+solution.reorganizeString("aa")+"\"");// ""}可行性:
maxFreq <= (n + 1) / 2贪心策略:
索引:
字符表示:
边界情况:
为什么可行性条件是(n+1)/2?
(n+1)/2可以处理两种情况为什么间隔放置策略有效?
优先队列为什么需要prev变量?