zoukankan      html  css  js  c++  java
  • 每日一题 为了工作 2020 0417 第四十六题

    /**
     * 问题:删除多余字符得到字典序最小的字符串
     *       给定一个全是小写字母的字符串str,删除多余的字符,使得每一种字符都只保留一个,
     *       并且要求最终结果字符串的字典序最小。
     * 举例:
     *      str = "acbc",删掉第一个'c',得到"abc",是所有字符串中字典序最小的。
     *      str = "dbcacbca",删掉第一个'b',第一个'c',第二个'c',第二个'a',得到"dabc"。
     *      是所有结果字符串字典序最小的。
     * 解答:
     *      不考虑怎么去删除,应当考虑怎么去挑选。str的结果字符串记为res,假设res的长度为
     * N,其中有k种不同的字符,那么res的长度为K。思路是怎么在str中从左到右依次挑选出res[0],
     * res[1],...,res[k-1]。举个例子,str[0..9]="baacbaccac",一共三种字符,所以要在str中
     * 从左到右依次找到res[0..2]。
     *
     * 流程:
     * 1.建立str[0..9]的字频统计,b有两个、a有四个、c有四个。
     * 2.从左往右遍历str[0..9],遍历到字符的字频统计减一,当发现某一种字符的字频统计已经为0时,
     * 遍历停止。在例子中当遍历完"baacb"时,字频统计b有0个、a有2个、c有3个,发现b的字频已经为
     * 0,所以停止遍历,当前遍历到str[4]。str[5..9]为"accac"已经没有b了,而流程是在str中从左
     * 到右依次挑选出res[0]、res[1]、res[2],所以,如果str[5..9]中的任何一个字符挑选成为res[0],
     * 之后过程是在挑选未知的右边继续挑选,那么一定会错过b字符,所以在str[0..4]上挑选res[0]。
     * 3.在str[0..4]上找到字典序最小的字符,即str[1]==‘a’,它就是res[0]。
     * 4.在挑选字符str[1]的右边,字符串为"acbaccac",删掉所有的'a'字符变为"cbccc",令str="cbccc",
     * 下面寻找str[1]。
     * 5.建立str[0..4]的词频索引,b有1个,c有4个。
     * 6.从左往右遍历str[0..4],遍历到的字符字频统计减一。当发现某一种字符的字频统计已经为0时,
     * 遍历停止。当遍历完"cb"时,字频统计b有0个、c有3个,发现b的字频已经为0,所以停止遍历,当前
     * 遍历到str[1]。str[2..4]为"ccc"已经没有b了。所以,如果str[2..4]中的任何一个字符挑选成为res[1],
     * 之后过程是在挑选未知的右边继续挑选,那么一定会错过b字符,所以在str[0..1]上挑选res[1]。
     * 7.在str[0..1]上找到字典序最小的字符,即str[1]==‘b’,它就是res[1]。
     * 8.在挑选字符str[1]的右边,字符串为"ccc",删掉所有的'b'字符变为"ccc",令str="cbccc",下面
     * 寻找str[2]。
     * 9.建立str[0..2]的词频索引,c有3个
     * 10.从左往右遍历str[0..2],遍历到的字符字频统计减一。当发现某一种字符的字频统计已经为0时,
     * 遍历停止。当遍历完"ccc"时,字频统计c有0个,发现c的字频已经为0,所以停止遍历,当前遍历到
     * str[2]。
     * 11.在str[0..2]上找到字典序最小的字符,即str[0]==‘c’,它就是res[2]。
     *
     * 总结:
     *      根据字频统计,遍历str时找到一个前缀str[0..R],然后再str[0..R]中找到最小ASCII码的字符
     * str[X],就是结果字符串的当前字符。然后令str=(str[X+1..R]去掉所有str[X]得到的字符串),重复
     * 整个流程,找到结果字符串的下一个字符,直到res生成完毕。
     */
    

      

    public class DeleteElementByDictsort {
        public static String deleteElements(String string){
    
            if (string.equals(" ") || string == null){
                return null;
            }
            char str[] = string.toCharArray();
            //小写字符的ASCII码值范围为[97-122],所以用长度为26的数组来做次数统计
            //如果map[i] > -1,则代表ASCII码值为i的字符的出现次数
            //如果map[i] == -1,则代表ASCII码值为i的字符不在考虑
            int map[]= new int[26];
            for (int i =0;i<str.length;i++){
                //如果出现一次该字符则该字符所对应的词频数组基值加一
                map[str[i]-'a']++;
            }
            char res[]=new char[26];
            int index = 0;
            int L = 0;
            int R = 0;
            while (R != str.length){
                //如果当前字符不在考虑则直接跳过
                //如果当前字符出现次数减一之后,后面还能出现,直接跳过
                if (map[str[R]-'a'] == -1 || --map[str[R]-'a'] > 0){
                    R++;
                }else {
                    //当前字符需要考虑,并且之后不会再次出现
                    //在str[L..R]上考虑所有字符找到ASCII码值最小的那个字符
                    int pick = -1;
                    for (int i = L;i <= R; i++){
                        if (map[str[i]-'a'] != -1 &&(pick == -1 || str[i]<str[pick])){
                            pick = i;
                        }
                    }
                    //将ASCII码最小的字符存放到挑选的结果中
                    res[index++] = str[pick];
                    //在上一个的for循环中,str[L..R]范围内每种字符出现的次数都减少了
                    // --map 操作将字符词频减少
                    //需要把str[pick+1..R]中每种字符出现的次数加回来
                    for (int i = pick+1;i <= R;i++){
                        if (map[str[i]-'a'] != -1){
                            map[str[i] -'a']++;
                        }
                    }
                    //选出ASCII码最小的字符,以后就不需要考虑了
                    map[str[pick]-'a'] = -1;
                    //继续执行该过程
                    L = pick + 1;
                    R = L;
                }
            }
            return String.valueOf(res , 0 ,index);
        }
    
        public static void main(String[] args) {
            String test = "acbvcccaabdcbbc";
            String result = deleteElements(test);
            System.out.println(result);
        }
    }
    

      

  • 相关阅读:
    建立一个简单的通讯录
    建立一个图书管理系统(oc)
    OC 学习第六天(敲代码时遇到的一些错误)
    Serv-U FTP Server 15.1.2学习笔记
    Myeclipse&Tomcat中遇到的部分问题---其一
    MySQL存储过程和函数(三)
    MySQL存储过程和函数(二)
    MySQL存储过程和函数(一)
    mybatis拦截器分页
    Java--最大子序列和实现
  • 原文地址:https://www.cnblogs.com/walxt/p/12719287.html
Copyright © 2011-2022 走看看