黑马程序员技术交流社区

标题: 一道编程题,字符串消除。 [打印本页]

作者: xpaibeyond    时间: 2014-9-11 10:31
标题: 一道编程题,字符串消除。
本帖最后由 xpaibeyond 于 2014-9-11 14:25 编辑

    一个字符串由abc三种字母组成,长度不限, 当ab或ba出现时可以用c替换, 当ac或ca出现时可以用b替换, 当bc或cb出现时可以用a替换, 如此反复替换,让字符串尽可能的短。 比如:abbbcc   结果:c
   
   有兴趣的朋友可以做一下。。。       把思路分享出来, 交流交流!!!





作者: 马嘉    时间: 2014-9-11 17:00
public class StringDemo {

        /**一个字符串由abc三种字母组成,长度不限, 当ab或ba出现时可以用c替换,
         * 当ac或ca出现时可以用b替换, 当bc或cb出现时可以用a替换, 如此反复替换,让字符串尽可能的短。
         *  比如:abbbcc   结果:c
         *  思路:是对字符串进行判断,对符合要求的字符串进行替换成对应的字符串
         *  
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                String str="abbbcc";
       
                while(ifDemo(str)){
                        str=show(str);
                        System.out.println(str);
                        continue;
                }
        }

        private static String show (String str) {//对包含的字符窜进行替换
                // TODO Auto-generated method stub
                if(str.indexOf("ab")!=-1)
//                        str=replace(str,"ab","c");
                        str=str.replaceAll("ab","c" );
                if(str.indexOf("ba")!=-1)
//                        str=replace(str,"ba","c");
                        str=str.replaceAll("ba","c" );
                if(str.indexOf("ac")!=-1)
//                        str=replace(str,"ac","b");
                        str=str.replaceAll("ac","b" );
                if(str.indexOf("ca")!=-1)
//                        str=replace(str,"ca","b");
                        str=str.replaceAll("ca","b" );
                if(str.indexOf("bc")!=-1)
//                        str=replace(str,"bc","a");
                        str=str.replaceAll("bc","a" );
                if(str.indexOf("cb")!=-1)
//                        str=replace(str,"cb","a");
                        str=str.replaceAll("cb","a" );
                return str;
        }
        private static boolean ifDemo(String str) {//创建方法用于判断字符窜是否包含指定的字符窜
                // TODO Auto-generated method stub
                if(str.indexOf("ab")!=-1)
                        return true;
                if(str.indexOf("ba")!=-1)
                        return true;
                if(str.indexOf("ac")!=-1)
                        return true;
                if(str.indexOf("ca")!=-1)
                        return true;
                if(str.indexOf("cb")!=-1)
                        return true;
                if(str.indexOf("bc")!=-1)
                        return true;
                       
                return false;
        }
我觉得要是用正则来做会更简单一点,但是我对正则还是不太熟悉,你要是有好的思路,也跟我分享一下哦
作者: 这个夏天的芬芳    时间: 2014-9-11 19:33
{:2_31:}{:2_31:}{:2_31:}{:2_31:}{:2_31:}{:2_31:}
作者: xpaibeyond    时间: 2014-9-11 23:12
马嘉 发表于 2014-9-11 17:00
public class StringDemo {

        /**一个字符串由abc三种字母组成,长度不限, 当ab或ba出现时可以用c替换,

这是我的思路:
                     1,对字符串格式校验(字符串是否为空和是否包含除abc外的字母等)。否(不合格),提示该字符串不合格。是,执行下面操作。
                     2,判断字符中是否包含两种字母(因为只有包含两种字母才能进行替换操作)。否,提示该字符串无需优化。是,执行下面操作。
                     3,获取字符串中出现次数最多的字母,并从该字母开始替换。
                     4,每次替换完后重复2,3的操作。

我是这么分析的,可能也不是最优的算法。。。
作者: MeryStyle    时间: 2014-9-11 23:30
我的思路:逐个遍历字符串的每个字符,如,第一次时判断第一个字符和第二个字符是否相同,不相同,将它门两个替换为第三个字符;相同,继续往下遍历,比较第二个字符与第三个是否相同…………以此类推之,直到所有字符都不能再替换为止。
作者: 迷失的独白    时间: 2014-9-12 01:54
楼主这道题不科学啊abbbcc

怎么看都应该是ab换算c,bb换算null,cc换算null才对啊
可是这道题却是ab换算c,bb换算b,bc换算a,c为c

这是按照楼主的意思写的,改动空间很大,大家指教

  1. import java.util.regex.Pattern;

  2. /**
  3. * 一个字符串由abc三种字母组成,长度不限,
  4. * 当ab或ba出现时可以用c替换, 当ac或ca出现时可以用b替换, 当bc或cb出现时可以用a替换,
  5. *  如此反复替换,让字符串尽可能的短。
  6. *  比如:abbbcc   结果:c
  7. * @author Administrator
  8. */
  9. /**
  10. * 定义正则表达式,不是连续重复的字符,
  11. * 替换功能,将符合标准的字符替换
  12. */

  13. public class ReplaceStr {

  14.         public static void main(String[] args) {
  15.                 String str = "abbbcc";
  16.                 new Replace(str);
  17.         }
  18. }

  19. class Replace {
  20.         // 定义正则表达式和字符标准
  21.         //定义不是连续两个重复的正则
  22.         private String regRepetition = "\\ba{2}\\b|\\bb{2}\\b|\\bc{2}\\b";
  23.         //检查是否与数组中的字符串相同,然后将未出现的字符串添加到另处
  24.         //这里还不成熟,正则表达式还是理解不清,所以有很大的改动空间
  25.         private String[] regMatch = { "ab", "ac", "ba",  "bc", "ca", "cb" };
  26.         private String strMatch = "cbcaba";
  27.         //两个存储字符串
  28.         private StringBuilder strb = new StringBuilder();
  29.         private StringBuilder parStrb = new StringBuilder();

  30.         // 初始化字符串
  31.         public Replace(String str) {
  32.                 strb.append(str);
  33.                 System.out.println("开始\t--------" + strb);
  34.                 while (true) {
  35.                         //判断字符串是都都是同一个字符
  36.                         if (Pattern.matches("a+|b+|c+", strb)) {
  37.                                 System.out.println("结束\t--------" + strb);
  38.                                 break;
  39.                         }
  40.                         parStrb.setLength(0);
  41.                         parStrb.append(strb);
  42.                         strb.setLength(0);
  43.                         replace(parStrb);
  44.                         System.out.println("\t--------" + strb);

  45.                 }
  46.         }

  47.         private void replace(StringBuilder str) {
  48.                 for (int x = 0; x < str.length();) {
  49.                         //如果是最后一个字符串直接添加到另处
  50.                         if (x == str.length() - 1) {
  51.                                 strb.append(str.charAt(x));
  52.                                 break;
  53.                         }
  54.                         //根据返回值让循环+1还是+2
  55.                         if (fun(str.substring(x, x + 2)) == 0) {
  56.                                 x++;
  57.                                 continue;
  58.                         }
  59.                         x = x + 2;
  60.                 }
  61.         }

  62.         // 循环替换
  63.         private int fun(String str) {
  64.                 //如果是重复的字符串,则将第一个字符添加到另处
  65.                 if (str.matches(regRepetition)) {
  66.                         strb.append(str.charAt(0));
  67.                         return 0;
  68.                 }
  69.                 else {
  70.                         //将符合的字符串添加到另处
  71.                         for (int x = 0; x < regMatch.length; x++) {
  72.                                 if (str.matches(regMatch[x])) {
  73.                                         strb.append(strMatch.charAt(x));
  74.                                         return 1;
  75.                                 }
  76.                         }
  77.                 }
  78.                 return 1;

  79.         }
  80. }
复制代码



作者: 谢建平    时间: 2014-9-12 05:23
这个感觉 没必要去排查只有abc额  不管有没有都不影响减缩
作者: 谢建平    时间: 2014-9-12 06:31
  1. package test;

  2. public class Test_01 {

  3.         /**
  4.          * @param args
  5.          */
  6.         public static void main(String[] args) {
  7.                 // TODO Auto-generated method stub

  8.                 String s1 = "abbbcc";
  9.                 String scut = cut(s1);
  10.                 System.out.print(scut);
  11.         }

  12.                        
  13.         public  static String cut(String s) //缩短的方法
  14.         {               
  15.                         //如果能缩    就缩
  16.                 while(isContain(s))
  17.                 {
  18.                         s=s.replaceAll("ab", "c");
  19.                         s=s.replaceAll("ba", "c");
  20.                         s=s.replaceAll("ac", "b");
  21.                         s=s.replaceAll("ca", "b");
  22.                         s=s.replaceAll("bc", "a");
  23.                         s=s.replaceAll("cb", "a");
  24.                 }
  25.                 return s;
  26.         }
  27.        
  28.                        
  29.         private static boolean isContain(String s1) //此方法判断是否能继续缩
  30.         {               
  31.                         //如果能缩 返回true 否则 false
  32.                 if(s1.contains("ab")||s1.contains("ba")||
  33.                                 s1.contains("ac")||s1.contains("ca")||s1.contains("bc")||s1.contains("cb"))
  34.                                 return true;
  35.                 return false;
  36.         }
  37. }
复制代码

作者: xpaibeyond    时间: 2014-9-12 10:00
迷失的独白 发表于 2014-9-12 01:54
楼主这道题不科学啊abbbcc

怎么看都应该是ab换算c,bb换算null,cc换算null才对啊

规则是:当ab或ba出现时可以用c替换, 当ac或ca出现时可以用b替换, 当bc或cb出现时可以用a替换。    没有替换为null的情况。

  这里用的是一个简单的字符串替换过程为例:abbbcc -> cbbcc -> abcc -> aac-> ab->c
作者: xpaibeyond    时间: 2014-9-12 10:14
谢建平 发表于 2014-9-12 06:31

  把字符串换成:aaaaaaaaaabbbbbbbbbbcccccccccc   结果为:cccccccccc   不是最优结果, 考虑代码重构。。
作者: xpaibeyond    时间: 2014-9-12 10:41
迷失的独白 发表于 2014-9-12 01:54
楼主这道题不科学啊abbbcc

怎么看都应该是ab换算c,bb换算null,cc换算null才对啊

       把字符串换成:aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc    结果为:结束        --------cccccccccccccccccc      结果不是最优。
作者: 迷失的独白    时间: 2014-9-12 12:14
xpaibeyond 发表于 2014-9-12 10:41
把字符串换成:aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc    结果为:结束         ...

没有出现你想要的结果,是因为你要替换的字符串的数量问题
根据你的要求当出现aa这种情况时,不予理会,直接往后找
知道找到ab为止,但是因为奇偶的问题,会导致c无法被转换
你现在把需要替换的字符串中的a或b减少一位,就会出现你想要的结果了
减少一个a,结果为b
较少一个b,结果为a

还有,替换null的意思是不替换

可是我发现你的替换过程是全部从头开始,而且只替换一次
我想问一下,你这道题哪里看的?是不是把题意理解错了。
一般情况应该是从头到围,12,34,56,78这样两个两个的替换,重复的也要这样算,坐标总是向后两位移动
根据的你的题意,我是两个两个的替换,但是字符为重复的时候,坐标向后一位移动,

作者: xpaibeyond    时间: 2014-9-12 12:52
迷失的独白 发表于 2014-9-12 12:14
没有出现你想要的结果,是因为你要替换的字符串的数量问题
根据你的要求当出现aa这种情况时,不予理会, ...

     我是这样写的,可能也不是最优的方法。    多指教!!

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

public class StringReplace {

        /**
         * 需求分析:一个abc三种小写字母组成的字符串,当ab或ba出现时可以用c替换,
         *                         当ac或ca出现时可以用b替换,当bc或cb出现时可以用a替换。
         *                         尽可能让字符串的长度变短。
         *
         *    例: aaaabbbccccccc
         *      替换后: c
         *   
         *    思路:1,对字符串格式校验(字符串是否为空和是否包含除abc外的字母等)。否(不合格),提示该字符串不合格。是,执行下面操作。
         *               2,判断字符中是否包含两种字母(因为只有包含两种字母才能进行替换操作)。否,提示该字符串无需优化。是,执行下面操作。
         *               3,获取字符串中出现次数最多的字母,并从该字母开始替换。
         *               4,每次替换完后重复2,3的操作。
         */
       
        public static void main(String[] args) {
                        String str="aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc";
//                        String str="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacccccccccccccccccc";
                       
                        Begin(str);
        }

        private static void Begin(String str) {
                                boolean flag=getContains(str);//检查字符是否包含两种字母。
                               
                                if(!flag){
                                         throw new RuntimeException("字符串非法或无需优化!!");
                                }
                  int count=0;//用于记录替换次数
                  while(flag){
                                         
                                  System.out.println(" 字符串 str=" + str + "      长度为:" + str.length());
                            
                            char ch=getCharMaxnum(str); //获取出现次数最多的字母
                            System.out.println("每次出现次数最多的字母:"+ch);
                          
                            str=stringReplace(str,ch);//对字符串按规则进行替换
                          
                                System.out.println(" 替换"+ (++count) + "次后str:" + str + "   长度为:" + str.length());
                                System.out.println("============================================");
                                System.out.println();
                               
                                flag=getContains(str);//检查字符是否包含两种字母。
                  }
        }
       
        /**
         * 对字符串按规则进行替换  ab|ba ->c   ac|ca ->b  bc|cb->a  
         * */
        private static String stringReplace(String str,char ch) {
                       
                        String regexA="(ab|ba)";
                        String regexB="(bc|cb)";
                        String regexC="(ac|ca)";
                        switch(ch){
                                case'a':{
                                                str=str.replaceAll(regexA, "c");
                                                str=str.replaceAll(regexC, "b");
                                               
                                        break;
                                }
                                case'b':{

                                                str=str.replaceAll(regexB, "a");
                                                str=str.replaceAll(regexA, "c");
                                        break;
                                }
                                case'c':{
                                                str=str.replaceAll(regexC, "b");
                                                str=str.replaceAll(regexB, "a");
                                        break;
                                }
                       
                        }
               
                return str;
        }

        /**
         * 判断字符串是否包含两种字母
         * */
        private static boolean getContains(String str) {
                if(str==null || "".equals(str)){
                        throw new RuntimeException("字符串为空!!");
                }
                if(str.contains("a") && str.contains("b")){
                        return true;
                }
                else if(str.contains("a") && str.contains("c")){
                        return true;
                }
                else if(str.contains("b") && str.contains("c")){
                        return true;
                }
               
                return false;
        }

        /**
         * 获取出现次数最多的字母
         * */
        private static char getCharMaxnum(String str) {
               
                if(str==null || "".equals(str)){
                        throw new RuntimeException("字符串为空!!");
                }
                char ch[] = str.toCharArray();
                Map<Character,Integer> map=new TreeMap<Character,Integer>();
                for(int i=0;i<ch.length;i++){
                        switch(ch){
                                case 'a': {
                                        if(map.get('a')==null){
                                                map.put('a',1);
                                                break;
                                        }
                                        map.put('a',map.get('a')+1);
                                        break;
                                }
                                case 'b':{
                                        if(map.get('b')==null){
                                                map.put('b',1);
                                                break;
                                        }
                                        map.put('b',map.get('b')+1);
                                        break;
                                }
                                case 'c':{
                                        if(map.get('c')==null){
                                                map.put('c',1);
                                                break;
                                        }
                                        map.put('c',map.get('c')+1);
                                        break;
                                }
                         default :{
                                 throw new RuntimeException("该字符串包含非法字符!!!");
                         }
                  }
           }
                //对象存储字母和个数的map进行排序
                List list=new ArrayList(map.entrySet());
                Collections.sort(list,new Comparator(){
                        public int compare(Object o1, Object o2) {
                                Map.Entry entry1=(Map.Entry)o1;
                                Map.Entry entry2=(Map.Entry)o2;
                                return ((Integer)entry1.getValue()).compareTo((Integer)entry2.getValue());
                        }
                });
               
                for(int i=0; list!=null && i<list.size();i++){
                       
                        Map.Entry<Character, Integer> entry=(Entry<Character, Integer>) list.get(i);
                        System.out.print(" " + entry.getKey()+":"+entry.getValue() + "  ");
                        if(list.size()==1){
                                return entry.getKey();
                        }
                        if(i==list.size()-1){
                                return entry.getKey();
                        }
                }
               
                return 0;
        }

}

作者: 迷失的独白    时间: 2014-9-12 13:20
xpaibeyond 发表于 2014-9-12 12:52
我是这样写的,可能也不是最优的方法。    多指教!!

import java.util.ArrayList;

为啥我感觉你理解的题意,和我理解的题意不同呢
这是你的解题abbbcc -> cbbcc -> abcc -> aac-> ab->c
这是我的解题abbbcc -> (ab-c,bb-(b)bc-a,c) cbac -> ab -> c
ab-c
bb重复-b,保留第二个b作为下一次替换
bc-a将第二个b和下一个c替换为a
c-c最后一个
cbac
cb-a
ac-b
ab
ab-c
结果c
作者: xpaibeyond    时间: 2014-9-12 13:47
迷失的独白 发表于 2014-9-12 13:20
为啥我感觉你理解的题意,和我理解的题意不同呢
这是你的解题abbbcc -> cbbcc -> abcc -> aac-> ab->c
这 ...

     你没看懂替换规则?    当ab或ba出现时可以用c替换, 当ac或ca出现时可以用b替换, 当bc或cb出现时 可以用a替换 。   

比如你说的:bb重复-b,保留第二个b作为下一次替换      不在规则范围内。

做这到题的方法有很多,每个人的思路可能都不一样。。
作者: xpaibeyond    时间: 2014-9-12 13:52
不会java 发表于 2014-9-12 13:21
这道题的关键思路应该是如何保持a的个数, b的个数, c的个数之间的平衡(尽量相等).
下午有空了再来把代码添 ...

     我还没尝试这样分析过,  很期待。。
作者: xiayoutianxia    时间: 2014-9-12 15:58
MeryStyle 发表于 2014-9-11 23:30
我的思路:逐个遍历字符串的每个字符,如,第一次时判断第一个字符和第二个字符是否相同,不相同,将它门两 ...

这个想法不错啊!!
作者: 迷失的独白    时间: 2014-9-12 17:55
bbbbcacbbabccabbbcabccaccbccaccbaaaabcbabaaacbbbbccabaccbcbccabacaaaccaaabbaaabcabacbabbbabababaabbabcbcbbcabbcccccbbbacbbaacbbabcaacaabbacabbabcccabaaccbbcacacbaccbcbaaabbbbcbcccaacbabccccccbbbacbbbb


楼主啊,这不是思路的问题了,而是大家理解题意根本就不同
我和5楼的哥们是认为顺序替换
而你认为的是挑着替换,你不按套路出牌啊
我现在都有点思维错乱了,真的不明白是自己的问题,还是这道题.....
作者: xpaibeyond    时间: 2014-9-12 19:20
迷失的独白 发表于 2014-9-12 17:55
bbbbcacbbabccabbbcabccaccbccaccbaaaabcbabaaacbbbbccabaccbcbccabacaaaccaaabbaaabcabacbabbbabababaabba ...

题目详情
给定一个字符串,仅由a,b,c 3种小写字母组成。当出现连续两个不同的字母时,你可以用另外一个字母替换它,如

有ab或ba连续出现,你把它们替换为字母c;
有ac或ca连续出现时,你可以把它们替换为字母b;
有bc或cb 连续出现时,你可以把它们替换为字母a。
你可以不断反复按照这个规则进行替换,你的目标是使得最终结果所得到的字符串尽可能短,求最终结果的最短长度。

      这是原题,我觉得我叙述得比它没什么区别吧。。     不管是顺序替换,还是选择替换,最终的目的是让任何一个字符串参与运算后都能变得尽可能的短。   

作者: 迷失的独白    时间: 2014-9-12 19:37
xpaibeyond 发表于 2014-9-12 19:20
题目详情
给定一个字符串,仅由a,b,c 3种小写字母组成。当出现连续两个不同的字母时,你可以用另外一个字 ...

我想问,你这道题全吗?
还是说,你参照网上的方法了?
网上的题可是有这么几句的
{
输入:字符串。长度不超过200,仅由abc三种小写字母组成。
输出:按照上述规则不断消除替换,所得到的字符串最短的长度。

例如:
        输入cab,输出2。因为我们可以把它变为bb或者变为cc。
        输入bcab,输出1。尽管我们可以把它变为aab -> ac -> b,也可以把它变为bbb,但因为前者长度更短,所以输出1。
}
如果是按照网上的这种题目做的话,你的方法无可厚非
如果不是,你这是坑啊!
作者: xpaibeyond    时间: 2014-9-12 20:10
迷失的独白 发表于 2014-9-12 19:37
我想问,你这道题全吗?
还是说,你参照网上的方法了?
网上的题可是有这么几句的

   :L:L, 本来就是这个题,     我描述的跟网上的有很大差别???  
作者: 迷失的独白    时间: 2014-9-12 20:28
xpaibeyond 发表于 2014-9-12 20:10
, 本来就是这个题,     我描述的跟网上的有很大差别???

你这就是坑啊!
你少了个举例,题意就差嗨了
而且我一般都是先写,写完了才去网上看别人怎么做的。
如果是按照网上的例子去做,这道题就简单多了
我也不至于......:'(:'(:'(
作者: xpaibeyond    时间: 2014-9-12 21:04
不会java 发表于 2014-9-12 16:17
写的比较仓促 有点乱, 不过可以用.

:handshake    不错, 要是有点注释读起来就更顺畅了。
作者: 卖艺人    时间: 2014-9-12 21:09
你这看着怎么那么像LZW编码。。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2