外观数组(leetcode38)

给定一个正整数 n ,输出外观数列的第 n 项。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

你可以将其视作是由递归公式定义的数字字符串序列:

  • countAndSay(1) = "1"
  • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

前五项如下:

1.    1
2.    11
3.    21
4.    1211
5.    111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"

 

要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成

然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组再将所有描述组连接起来。

 

解析:

两种方式,循环和递归

可以用一个变量记录一个描述组的字符,同时记录描述组字符的个数;

也可以直接记录一个描述组的开始索引,以及最后一个不相同的位置;

然后得到描述字符的个数,以及描述字符。最后注意边界条件,考虑n=1的情况,把边界加入;

package com.vincent.leetcode;

public class leetcode38 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int n=8;
        System.out.println(countAndSay1(n));
    }

    
    //循环
    public static String countAndSay(int n) {
        
         if(n==1){
            return "1";
        }
        
        int i=1;
        StringBuilder result = new StringBuilder();
        StringBuilder preResult = new StringBuilder();
        preResult.append("1");
        for(;i<n;i++){
            Character ch;
            int count=1;
            int j=0;
            for(;j<preResult.length()-1;j++){
                ch = preResult.charAt(j);
if(preResult.charAt(j+1)==preResult.charAt(j)){//如果j位置的字符与j+1位置的字符相同,则count加1
                    count++;
                }else{//如果j和j+1位置的字符不同,则说明可以把该字符的个数和该字符加入结果了,然后count重置为1,开始统计下个字符连续出现的数量
                    result.append(count);
                    result.append(ch);
                    count=1;
                }
            }
            if(j<preResult.length()){//加入最后一个字符及它的个数
                result.append(count);
                result.append(preResult.charAt(preResult.length()-1));
            }
            preResult.delete(0, preResult.length());//清理上一个结果
            preResult.append(result.toString());
            result.delete(0, result.length());
        }
        return preResult.toString();
    }
    
    //循环
    public static String countAndSay1(int n) {
        
        StringBuilder preResult = new StringBuilder();
        //记录当前行的字符串,即n为i时对应的字符串
        StringBuilder result = new StringBuilder();
        preResult.append(1);
        for(int i=1;i<n;i++){
            
            //记录每个数字的开始索引
            int start = 0;
            for(int j=1;j<preResult.length();j++){
                //当数字发生改变时执行
                if(preResult.charAt(j)!=preResult.charAt(start)){
                    result.append(j-start).append(preResult.charAt(start));
                    start = j;
                }
            }
            //字符串最后一个字符,可以考虑i=1时;
            result.append(preResult.length()-start).append(preResult.charAt(start));
            preResult.delete(0, preResult.length());
            preResult.append(result);
            result.delete(0, result.length());
            
        }
        
        return preResult.toString();
    }
    
    //递归
    public static String countAndSay2(int n) {
        //递归终止条件
        if(n==1){
            return "1";
        }
        //获取到上一层的字符串
        String preResult = countAndSay2(n-1);
        StringBuilder result = new StringBuilder();
        //记录每个数字的开始索引
        int start = 0;
        for(int i=1;i<preResult.length();i++){
            //当数字发生改变时执行
            if(preResult.charAt(i)!=preResult.charAt(start)){
                result.append(i-start).append(preResult.charAt(start));
                start = i;
            }
        }
        //字符串最后一个数字
        result.append(preResult.length()-start).append(preResult.charAt(start));
        return result.toString();
    }
}

 

posted @ 2021-04-12 23:46  Vincent-yuan  阅读(88)  评论(0编辑  收藏  举报