题目描述
给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = "aab"
输出: "aba"
示例 2:输入: S = "aaab"
输出: ""
注意:S 只包含小写字母并且长度在[1, 500]区间内。
我的解题思路:遍历字符串用一个长度为26的桶数组记录每个字符的个数,以字符长度为外层for判断,内层遍历数组找到数量最大字母数组下标和数值以及第二大字母在数组下标和数值,将其拼接在新字符串中,在判断如果只剩一种字符的时候,数值如果大于1则返回空字符串,为1则追加数组,后续将数组对应字符数量相减,字符长度相减
func reorganizeString(S string) string {
var str string
var array [26]int
var strLen = len(S)
for i:=0;i<strLen;i++{
array[S[i]-97]++
}
for strLen>0{
var firstMax,secondMax int
var firstIndex,secondIndex int
for i:=0;i<len(array);i++{
if array[i]!=0 && array[i]>firstMax{
secondMax = firstMax
secondIndex = firstIndex
firstMax = array[i]
firstIndex = i
}else if array[i]!=0 && array[i]>secondMax{
secondMax = array[i]
secondIndex = i
}
}
for j:=0;j<secondMax;j++{
str = str+string(rune(firstIndex+97))+string(rune(secondIndex+97))
}
if secondMax == 0 && firstMax>1{
return ""
}else if secondMax == 0 && firstMax==1 {
str = str +string(rune(firstIndex+97))
strLen = strLen-firstMax
}
array[firstIndex] = array[firstIndex]-secondMax
array[secondIndex] = 0
strLen = strLen-secondMax*2
}
return str
}
官方解题思路一:用堆维护一个非空字符,每次取出两个字符拼接,其中涉及堆的概念和运用还需好好理解
var cnt [26]int
type hp struct{ sort.IntSlice }
func (h hp) Less(i, j int) bool { return cnt[h.IntSlice[i]] > cnt[h.IntSlice[j]] }
func (h *hp) Push(v interface{}) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() interface{} { a := h.IntSlice; v := a[len(a)-1]; h.IntSlice = a[:len(a)-1]; return v }
func (h *hp) push(v int) { heap.Push(h, v) }
func (h *hp) pop() int { return heap.Pop(h).(int) }
func reorganizeString(s string) string {
n := len(s)
if n <= 1 {
return s
}
cnt = [26]int{}
maxCnt := 0
for _, ch := range s {
ch -= 'a'
cnt[ch]++
if cnt[ch] > maxCnt {
maxCnt = cnt[ch]
}
}
if maxCnt > (n+1)/2 {
return ""
}
h := &hp{}
for i, c := range cnt[:] {
if c > 0 {
h.IntSlice = append(h.IntSlice, i)
}
}
heap.Init(h)
ans := make([]byte, 0, n)
for len(h.IntSlice) > 1 {
i, j := h.pop(), h.pop()
ans = append(ans, byte('a'+i), byte('a'+j))
if cnt[i]--; cnt[i] > 0 {
h.push(i)
}
if cnt[j]--; cnt[j] > 0 {
h.push(j)
}
}
if len(h.IntSlice) > 0 {
ans = append(ans, byte('a'+h.IntSlice[0]))
}
return string(ans)
}
复杂度分析
时间复杂度:O(nlog∣Σ∣+∣Σ∣),其中 nn 是字符串的长度,Σ 是字符集,在本题中字符集为所有小写字母,∣Σ∣=26。
遍历字符串并统计每个字母的出现次数,时间复杂度是 O(n)。空间复杂度:O(∣Σ∣),其中Σ 是字符集,在本题中字符集为所有小写字母,∣Σ∣=26。这里不计算存储最终答案字符串需要的空间(以及由于语言特性,在构造字符串时需要的额外缓存空间),空间复杂度主要取决于统计每个字母出现次数的数组和优先队列。
官方思路二:基于计数的贪心算法
func reorganizeString(s string) string {
n := len(s)
if n <= 1 {
return s
}
cnt := [26]int{}
maxCnt := 0
for _, ch := range s {
ch -= 'a'
cnt[ch]++
if cnt[ch] > maxCnt {
maxCnt = cnt[ch]
}
}
if maxCnt > (n+1)/2 {
return ""
}
ans := make([]byte, n)
evenIdx, oddIdx, halfLen := 0, 1, n/2
for i, c := range cnt[:] {
ch := byte('a' + i)
for c > 0 && c <= halfLen && oddIdx < n {
ans[oddIdx] = ch
c--
oddIdx += 2
}
for c > 0 {
ans[evenIdx] = ch
c--
evenIdx += 2
}
}
return string(ans)
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reorganize-string/solution/zhong-gou-zi-fu-chuan-by-leetcode-solution/