怎么让百度收录网站,wordpress更换域名后,高境网站建设,酒水销售网站模板重构字符串
问题描述
给定一个字符串 s#xff0c;检查是否能重新排列其中的字符#xff0c;使得任意两个相邻的字符都不相同。
如果可以重新排列#xff0c;返回任意一个满足条件的字符串。如果不能#xff0c;返回空字符串 。
示例#xff1a;
输入: s 检查是否能重新排列其中的字符使得任意两个相邻的字符都不相同。如果可以重新排列返回任意一个满足条件的字符串。如果不能返回空字符串。示例输入: s aab 输出: aba 输入: s aaab 输出: 算法思路核心思想是优先处理出现频率最高的字符。关键可行性如果某个字符的出现次数超过(n 1) / 2n为字符串长度则无法重构例如长度为4最多允许2个相同字符长度为5最多允许3个相同字符贪心策略总是优先放置当前剩余最多的字符要避免与前一个字符相同方法优先队列最大堆按字符频率排序每次取出频率最高的字符间隔放置先将最高频字符放在偶数位置再填充其他字符代码实现方法一优先队列importjava.util.*;classSolution{/** * 使用优先队列重构字符串确保相邻字符不同 * * param s 输入字符串 * return 重构后的字符串如果无法重构返回空字符串 */publicStringreorganizeString(Strings){// 1: 统计每个字符的频率int[]charCountnewint[26];for(charc:s.toCharArray()){charCount[c-a];}// 2: 检查可行性 - 任何字符频率不能超过 (n1)/2intns.length();for(intcount:charCount){if(count(n1)/2){return;}}// 3: 构建最大堆按频率排序// 堆中存储 [字符, 频率]PriorityQueueint[]maxHeapnewPriorityQueue((a,b)-b[1]-a[1]);for(inti0;i26;i){if(charCount[i]0){maxHeap.offer(newint[]{i,charCount[i]});}}// 4: 重构字符串StringBuilderresultnewStringBuilder();int[]prevnull;// 记录上一次使用的字符避免连续使用while(!maxHeap.isEmpty()){// 取出频率最高的字符int[]currentmaxHeap.poll();// 将字符添加到结果中result.append((char)(acurrent[0]));current[1]--;// 频率减1// 如果上一个字符还有剩余重新放回堆中if(prev!nullprev[1]0){maxHeap.offer(prev);}// 更新prev为当前字符prevcurrent;}// 如果结果长度等于原字符串长度说明重构成功returnresult.length()n?result.toString():;}}方法二间隔放置classSolution{/** * 使用间隔放置策略重构字符串 * * param s 输入字符串 * return 重构后的字符串如果无法重构返回空字符串 */publicStringreorganizeString(Strings){// 1: 统计字符频率int[]charCountnewint[26];intmaxFreq0;charmaxChar ;for(charc:s.toCharArray()){charCount[c-a];if(charCount[c-a]maxFreq){maxFreqcharCount[c-a];maxCharc;}}// 2: 检查可行性intns.length();if(maxFreq(n1)/2){return;}// 3: 创建结果字符数组char[]resultnewchar[n];// 4: 先将最高频字符放在偶数位置 (0, 2, 4, ...)intindex0;while(charCount[maxChar-a]0){result[index]maxChar;index2;charCount[maxChar-a]--;}// 5: 填充其他字符for(inti0;i26;i){while(charCount[i]0){// 如果偶数位置已满切换到奇数位置if(indexn){index1;}result[index](char)(ai);index2;charCount[i]--;}}returnnewString(result);}}算法分析时间复杂度方法一O(n log k)k是不同字符的数量最多26实际为O(n)方法二O(n) - 只需要遍历字符串常数次空间复杂度所有方法O(1) - 字符计数数组大小固定为26结果字符串空间不计入空间复杂度算法过程1s “aab”方法一优先队列字符频率a2, b1堆[(a,2), (b,1)]步骤取a结果“a”堆[(b,1)]prev(a,1)取b结果“ab”堆[(a,1)]prev(b,0)取a结果“aba”堆[]prev(a,0)返回aba方法二间隔放置最高频字符a(频次2)先放a位置0,2 → [‘a’, ?, ‘a’]放b位置1 → [‘a’, ‘b’, ‘a’]返回aba2s “aaab”字符频率a3, b1长度4最大允许频次(41)/22a的频次3 2返回3s “vvvlo”字符频率v3, l1, o1长度5最大允许频次3v的频次3 3可以重构间隔放置v在位置0,2,4 → [‘v’,?, ‘v’,?, ‘v’]填充l,o位置1,3 → [‘v’,‘l’,‘v’,‘o’,‘v’]返回vlvov测试用例publicstaticvoidmain(String[]args){SolutionsolutionnewSolution();// 测试用例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边界情况 - 最大频次刚好等于(n1)/2System.out.println(Test 6: \solution.reorganizeString(aaaabc)\);// 长度6max4(61)/2343 → // 测试用例7长度为奇数的最大频次System.out.println(Test 7: \solution.reorganizeString(aaabc)\);// 长度5max3(51)/23 → 可以重构// 测试用例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贪心策略优先处理高频字符避免最后无法放置间隔放置确保相同字符不相邻索引先使用偶数索引0,2,4…偶数索引用完后使用奇数索引1,3,5…保证了最优的字符分布字符表示使用数组索引0-25表示’a’-‘z’节省空间且访问高效边界情况空字符串、单字符、两字符等特殊情况最大频次等于边界值的情况常见问题为什么可行性条件是(n1)/2对于偶数长度n最多能放置n/2个相同字符对于奇数长度n最多能放置(n1)/2个相同字符统一写成(n1)/2可以处理两种情况为什么间隔放置策略有效最高频字符占据最优位置间隔最大其他字符频率更低更容易找到合适位置偶数位置用完后奇数位置必然足够优先队列为什么需要prev变量防止连续使用同一个字符将刚使用的字符暂时移除下一轮再放回