报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1. 1 2. 11 3. 21 4. 1211 5. 111221
- 1 被读作 "one 1" ("一个一") , 即 11。
- 11 被读作 "two 1s" ("两个一"), 即 21。
- 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
输入: 1 输出: "1" 输入: 4 输出: "1211"
理解题意:
首先我们还是列举一下每个数的输出吧
第几次 | 输出 |
---|---|
1 | 1 |
2 | 11 |
3 | 21 |
4 | 1211 |
5 | 111221 |
6 | 312211 |
7 | 13112221 |
8 | 1113213211 |
9 | 31131211131221 |
从上面我们可以看出来,对一个数说出来有两种情况:
- 多个相邻一样:n个几
- 相邻不一样:1个几
那函数中重要的思想就是:
- 遍历上一次的输出
- 然后比较相邻的数
- 如果是一样的话,那就在找下一位
- 如果是不一样的话,那就要添加到数组中
核心代码:
func say(bs []byte) []byte { result := make([]byte, 0) x, y := 0, 1 for x < len(bs) { //取出字节数组中的每一个 //判断相邻位置的是否是一样 //当是一样的话,那就继续,找到有多少个是一样的 //当不是一样的话,那就是一个几 //这里要保证y不能超过bs的长度,不然会panic for y < len(bs) && bs[x] == bs[y] { y++ } //第二个参数是指有多少个一样的 // (这里需要注意一点,一定要加上'0',不然字节不对,'0'代表的字节是48, // 如果不加上'0',byte(y-x)就是byte(1),这是不对的) //第三个参数是指说出来的那个数 result = append(result, byte(y-x+'0'), bs[x]) //跳过相同的数 x = y } return result }
当然我们肯定要一开始就设定第一次的输出为'1'
func countAndSay(n int) string { if n == 1 { return "1" } bs := []byte{'1'} for i := 2; i <= n; i++ { bs = say(bs) } return string(bs) }
为什么要用字节数组呢?因为转字符串简单呀!!!