给定一个字符串S
,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = "aab" 输出: "aba"
示例 2:
输入: S = "aaab" 输出: ""
注意:
S
只包含小写字母并且长度在[1, 500]
区间内。
解题思路:
任务调度问题,排序。本题有点像之前的一个任务调度问题,由于题量太大,忘了哪一个。。。
- 统计当前字符串各个字符的个数,然后按照数量多少排序,如果数量一样,则按照字符大小排序,最终得到vector<pair<char,int>>mp,pair<char,int>中char代表字符,int代表数量。
- 假设字符总数是num,当前排序后的最大数量mp[0].second。如果2*mp[0].second>num+1,那么直接返回“”,必然有多余的字符。如果2*mp[0].second==num+1。第一个字符必然是mp[0].first,之后的成对即可,注意每一对都应该是mp[0].first在后,这样可以防止当前末尾与下一层的开始一样。如果,2*mp[0].second<num+1,直接组成mp[0].second对字符即可。
- 如果遇到2*mp[0].second<num+1情况,将mp[0].second对字符加入结果之后,mp中必然还有剩余的字符,对剩余的字符再次排序重复2过程即可。不过不一样的是,此刻结果字符串已经不为空了,当遇到2*mp[0].second>num+1的情况,应该先考虑是否能将多余的插入之前已经确定的结果,能则插入,不能则返回""。
class Solution { public: static bool cmp(pair<char, int> a, pair<char, int> b) { if (a.second == b.second) return a.first < b.first; return a.second > b.second; } string reorganizeString(string S) { vector<pair<char, int>> mp; int i, size = S.size(); for (i = 1; i <= 26; i++) mp.push_back({ 'a' + i - 1,0 }); for (i = 1; i <= size; i++) mp[S[i - 1] - 'a'].second++; sort(mp.begin(), mp.end(), Solution::cmp); int num = size; string res; while (num > 0) { if (mp[0].second * 2 > num + 1) { //在已有的字符串中查找mp[0].second*2 - num - 1个可以插入mp[0].first的位置,不包括末尾 int sum = mp[0].second * 2 - num - 1; for (i = 0; i < res.size(); i++) { if (sum>0&&i == 0 && res[0] != mp[0].first) { res.insert(res.begin(), mp[0].first); sum--; num--; mp[0].second--; } else { if (sum > 0 && res[i] != mp[0].first&&res[i - 1] != mp[0].first) { res.insert(res.begin()+i, mp[0].first); sum--; num--; mp[0].second--; } } } if (sum > 0) return ""; } if (mp[0].second * 2 == num + 1) { res.push_back(mp[0].first); num--; mp[0].second--; } int pos = 1; while (mp[0].second > 0) { res.push_back(mp[pos].first); mp[pos].second--; res.push_back(mp[0].first); mp[0].second--; num -= 2; if (mp[pos].second == 0&&pos!=25) pos++; } sort(mp.begin(), mp.end(), Solution::cmp); } return res; } }; |