767. Reorganize String

767. Reorganize String

1. 题目

Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other are not the same.
If possible, output any possible result. If not possible, return the empty string.
Example 1:
Input: S = “aab”
Output: “aba”
Example 2:
Input: S = “aaab”
Output: “”
Note:
S will consist of lowercase letters and have length in range [1, 500].

2. 题目分析
重构字符串,使得相邻的字符不能相同,输出重构的字符串;如果一定存在相邻的字符相同的情况,则输出“”。开始时,我没有任何想法解决判断是否能将字符串改成响铃字符不相同的新字符串,直到看完答案才发现,原来只要先统计每个字符出现的次数,然后判断找出现最大的次数的字符,判断该字符的次数是否超过总字符串的长度的一半,我们知道如果要使某个字符不能出现相邻的情况,那么出现的次数最大的时候,即是每空一个位置插入该字符,次数为总长度的1/2。

3. 解题思路
判断完字符串是否能重构成相邻字符不相同的字符的情况,接下来是进行真正的开始重构。
开始想法是,将所有字符按出现次数从大到小排序,然后不断循环,依次把字符放到新字符中,然后该字符出现的次数减1,直到每个字符的次数都为0跳出循环。
如:abbaac ,a:3, b:2, c:1
则,重构是,a b c a b a,是否发现好像能实现题目要求?开开心心的提交后发现有些用例过不了,如: lovvv , l:1, o:1, v:3
按我的逻辑,重构后是, v l o v v,发现了什么?真实答案应该是: v l v o v
我发现只有当某个字符出现的次数是总长度的1/2时,才会出现这种情况,然后开始打补丁,吧这种情况单独领出来处理,但发现在stringBuild中没办法判断某个下标的字符是否为空,只有通过先填充特定的字符,然后判断才行,所以果断放弃了。

最后看网上的思路,也是先统计每个字符出现的次数,然后使用优先队列,对字符按字符出行的次数进行降序排序,之后两个两个字符弹出,即每次弹出当前出现次数最多的前两个字符,然后将它们两个对应的count频率-1,再次把这两个字符放入队列,继续弹出……这样处理是为了保证每相邻的两个字符一定是不相同的。

4. 代码实现(java)

package com.algorithm.leetcode.sort;

import java.util.*;

/**
 * Created by 凌 on 2019/1/19.
 * 注释:
 */
public class ReorganizeString {
    public static void main(String[] args) {
//        String S = "vvvlo";
//        String S = "aaab";
//        String S = "aab";
        String S = "baaba";
        String result = reorganizeString(S);
        System.out.println(result);
    }
    public static String reorganizeString(String S) {
        if (S == null || S.length() <= 2){
            return S;
        }
        int[] count = new int[26];
        for (int i = 0; i < S.length(); i++) {
            count[S.charAt(i) - 'a']++;
        }
        int max = 0;
        PriorityQueue<CharAndCount> queue = new PriorityQueue<CharAndCount>(new Comparator<CharAndCount>() {
            @Override
            public int compare(CharAndCount o1, CharAndCount o2) {
                return o2.count - o1.count;
            }
        });
        CharAndCount charAndCount;
        for (int i = 0; i < 26; i++) {
            if (count[i] > 0){
                charAndCount = new CharAndCount((char)('a' + i),count[i]);
                queue.add(charAndCount);
            }
            if (count[i] > max){
                max = count[i];
            }
        }
        //如果发现有个字符的数量大于字符串的总长度的一半,那么一定存在两个相邻的字符是相同的
        if (max > (S.length() + 1)/2){
            return "";
        }

        StringBuilder result = new StringBuilder();
        while (queue.size() > 1){
            CharAndCount charAndCount1 = queue.poll();
            CharAndCount charAndCount2 = queue.poll();
            result.append(charAndCount1.ch);
            result.append(charAndCount2.ch);
            
            if (--charAndCount1.count > 0){
                queue.add(charAndCount1);
            }
            if (--charAndCount2.count > 0){
                queue.add(charAndCount2);
            }
        }

        if (queue.size() > 0){
            result.append(queue.poll().ch);
        }
        return result.toString();
    }
}
class CharAndCount{
    char ch;
    int count;

    public CharAndCount(char ch, int count) {
        this.ch = ch;
        this.count = count;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值