关于一道题的思考

题目详情

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


  1. 有ab或ba连续出现,你把它们替换为字母c;
  2. 有ac或ca连续出现时,你可以把它们替换为字母b;
  3. 有bc或cb 连续出现时,你可以把它们替换为字母a。


你可以不断反复按照这个规则进行替换,你的目标是使得最终结果所得到的字符串尽可能短,求最终结果的最短长度。


输入:字符串。长度不超过200,仅由abc三种小写字母组成。

输出: 按照上述规则不断消除替换,所得到的字符串最短的长度。


例如:输入cab,输出2。因为我们可以把它变为bb或者变为cc。

          输入bcab,输出1。尽管我们可以把它变为aab -> ac -> b,也可以把它变为bbb,但因为前者长度更短,所以输出1。

 

public class Main {
	
	 private static int minLength=1;
	 
	 public static int minLength(String s) {
		s=s.replace("^(\\s+)|(\\s+)$","");
		if(checkStr(s)){
			changeStr(s,1);
		}else{
			try {
				throw new Exception("输入的字符串不符合格式要求!");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return minLength;
	}
	 
	/**
	 * 每次取字符串的前三个字符进行递归操作
	 * <pre>
	 *     需判断操作的起始下标,如cccabacab的前三个字符为c,则保留前1个c,从ccabacab中取前三个操作。
	 * <pre>
	 * @param s
	 */
	public static void changeStr(String s,int startIndex){
	      if(s.length()<3){
	    	  if(s.length()==2){
	    		  String str=changeChar(s.charAt(0),s.charAt(1));
	    		  System.out.println(str);
	    		  minLength=str.length();
	    	  }
	    	  return;
	      }else{
	    	  String remainStr="";
	    	  if(startIndex==s.length()){ 
	    		  minLength=s.length();
	    		  return; 
	    	  }
			
	    	  if(startIndex<3){
	    		  startIndex=0;
	    	  }else{
	    		  startIndex=startIndex-2;
	    		  remainStr=s.substring(0,startIndex);
	    	  }
	    	  
	          char ch1=s.charAt(startIndex); 
	          char ch2=s.charAt(startIndex+1); 
	          char ch3=s.charAt(startIndex+2); 
	          String new_ch=changeChar(ch2,ch3);
	          String newStr="";
	          
	          //取前三个字符两两交换,初始时第二个与第三个
	          if(new_ch.length()==2){//如果交换的字符相等则必须交换另外两个
	        	  
	        	  new_ch=changeChar(ch1,ch2);
	              newStr=remainStr+new_ch+ch3+s.substring(startIndex+3);
	              
	          }else if(String.valueOf(ch1).equals(new_ch)){//如果交换后的字符与第一个相同,考虑第四个字符的情况
	        	  
	              if(s.length()>3){
	            	  char ch4=s.charAt(startIndex+3);
	            	  if(ch4!=ch1){
	            		  newStr=remainStr+ch1+new_ch+s.substring(startIndex+3);
	            	  }else{
	            		  new_ch=changeChar(ch1,ch2);
			              newStr=remainStr+new_ch+ch3+s.substring(startIndex+3);
		            	  
	            	  }
	              }else{
	            	  new_ch=changeChar(ch1,ch2);
		              newStr=remainStr+new_ch+ch3+s.substring(startIndex+3);
	              }
	          }else{
	        	  newStr=remainStr+ch1+new_ch+s.substring(startIndex+3);
	          }
	          
	          startIndex=startIndex(newStr);
	          changeStr(newStr,startIndex);  
	      }
	  }
	  
	
	/**
	 * 开始交换字母的起始下标
	 * <pre>
	 *     如:bbbbca 从第三个b开始操作,即前面的bb保留,操作bca 
	 * <pre>
	 * @param s
	 * @return
	 */
	  public static int startIndex(String s){
		  int startIndex=1;
		  char[] chs=s.toCharArray();
    	  for(int i=1;i<chs.length;i++){
    		  if(chs[i]!=chs[i-1]){
    			  break;
    		  }else{
    			  startIndex++; 
    		  }
    		
    	  }
    	  return startIndex;
	  }
	
	  
	  public static String changeChar(char c1,char c2){
	          if((c2+c1)==195){
	               return String.valueOf((char)99);
	          }else if((c2+c1)==196&&c1!=c2){
	               return String.valueOf((char)98);
	          }else if((c2+c1)==197){
	        	  return String.valueOf((char)97);
	          }else{
	              return String.valueOf(new char[]{c1,c2});
	          }
	  
	  }
	  
	  public static boolean checkStr(String s){
		  if(s.equals("")||s==null){
			  return false;
		  }
		  
		  char[] chs=s.toCharArray();
		  for(int i=0;i<chs.length;i++){
			  if(chs[i]=='a'||chs[i]=='b'||chs[i]=='c'){
			      continue; 
			  }else{
				  return false;
			  }
		  }
		  return true;
	  }
	
	public static void main(String[] agrs){

        	String s="abcbca" ;
        
		 //changeStr(s,1);
		int mixLen=minLength(s);
	    System.out.println(minLength);
		 
		 
	}

}


 【2016-12-28  修改】: 

dp - 分析:


 字符串abc转换结果有 abc -> {cc,aa} 
 
 字符串abcb的转换结果分两种:
 
    (1)在字符串abc的所有结果集的基础上合并,即有{cc(b),aa(b)} -> {b}
 
    (2)另一种是字符串的ab(cb)转换 -> {aba}, {aba}的转换为在字符串ab上的集合的基础上转换, 
         字符aba的转换重复(1),(2)步骤,最终 abcb -> {aba} ->{b},所以字符串abcb ->{b}


     (3) 合并(1),(2)的结果集,返回最终字符串abcb的所有合并结果,结果由容器去掉重复。

package com.davinci;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

public class MyTest {
	
	public String getMergeStr(String str){
		ArrayList<HashSet<String>> arrList = new ArrayList<HashSet<String>>();
		HashSet<String> set = new HashSet<String>();
		set.add(String.valueOf(str.charAt(0)));
		arrList.add(set);
		
		for(int i =1 ;i<str.length();i++){
			HashSet<String> prevResult = arrList.get(i-1);
			char prevChar = str.charAt(i-1); 
	        char currChar = str.charAt(i); 
	        HashSet<String>  currentResult = transform(prevResult,currChar);
	        
	        if(i-2 >=0 ){
	        	HashSet<String> prevPrevResult = arrList.get(i-2);
	        	if(prevChar != currChar){
	        	    String mergerStr = toMergeStr(String.valueOf(prevChar),currChar);
	        	    HashSet<String> result = transform(prevPrevResult,mergerStr.charAt(0));
	        	    currentResult.addAll(result);
	        	}
	        }
	     
	        arrList.add(i, currentResult);
		}
		
		//返回结果
		HashSet<String> l = arrList.get(str.length()-1);
	    return Arrays.deepToString(l.toArray());
	}
	
	public HashSet<String> transform(HashSet<String> prevResult , char c){
		HashSet<String> set = new HashSet<String>();
		for(String str : prevResult){
			String result = toMergeStr(str,c);
			set.add(result);
		}
		return set;
	}
	
	/**
	 * 返回合并的字符
	 * <p>
	 *    e.g  "aaaa"字符串追加字符'b'后,经转换,最终得到的是"b"
	 *  
	 * </p>
	 * @param str  由字符{a,b,c}组成
	 * @param c    字符 [a|b|c]
	 * @return
	 */
	public String toMergeStr(String str , char c){
		int len = str.length();
		char firstChar = str.charAt(0);
		boolean isOdd = (len & 1)== 1 ? true : false;
		
		if(c == firstChar){  //相同字符,添加后面
			str = str + c ;
			return str;
		}else{
			if(isOdd){ //奇位数
                if((c +firstChar) == 195 ){ // a + b = 97 + 98
                	return String.valueOf((char)99);
                }
                if((c +firstChar) == 196 ){
                	return String.valueOf((char)98);
                }
                if((c +firstChar) == 197 ){
                	return String.valueOf((char)97);
                }
			}else{
				return String.valueOf(c);
			}
		}
		return str;
	}
	
}



结果:

输入:bcab
结果:[b, bbb]

输入:cab
结果:[bb, cc]

输入:abcabc
结果:[cc, aa, aaaa, cccc]







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值