题目描述
我们构建了一个包含 n 行( 索引从 1 开始 )的表。首先在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。
例如,对于 n = 3 ,第 1 行是 0 ,第 2 行是 01 ,第3行是 0110 。
给定行数 n 和序数 k,返回第 n 行中第 k 个字符。( k 从索引 1 开始)
示例 1:
输入: n = 1, k = 1
输出: 0
解释: 第一行:0
示例 2:
输入: n = 2, k = 1
输出: 0
解释:
第一行: 0
第二行: 01
示例 3:
输入: n = 2, k = 2
输出: 1
解释:
第一行: 0
第二行: 01
提示:
1 <= n <= 30
1 <= k <= 2n - 1
解题思路
思路1:根据题目的意思进行模拟,内存超出限制,大家应该都没有问题,不好想的是第二种思路。
思路2:先多写几个测试的样例,我们先来发现一个规律,最后我们会发现,这是一道关于递归+(位运算)+脑筋急转弯类型的题目。
第一行仅有一个 0,然后接下来的每一行可以由上一行中 0替换为 01,1替换为 10来生成。
如果是第一层,直接返回0,否则求它的父亲。(n,k)的父亲的位置,就是(n-1,(k+1)/2),第二个参数代表k/2向上取整。而某个位置是左孩子还是右孩子,可以判断k是否为奇数,如果是奇数,就是左孩子,那就应该与父亲相同,否则相反。这可以通过异或实现。如果是奇数,k%2等于1,否则k%2等于0,而0异或一个数不改变值,所以我们将k%2取反再与父亲异或即可
实现代码
内存超出限制的代码:
class Solution {
public int kthGrammar(int n, int k) {
StringBuilder sb=new StringBuilder("0");
for(int i=0;i<n/2;i++){
StringBuilder temp=new StringBuilder("");
String str=sb.toString();
for(int j=0;j<str.length();j++){
if(str.charAt(j)=='0'){
temp.append("01");
}else{
temp.append("10");
}
}
sb=temp;
}
return sb.toString().charAt(k-1)-'0';
}
}
正确的代码:
class Solution {
public int kthGrammar(int N, int K) {
return recursion(N, K - 1);
}
public int recursion(int N, int k){
if(N == 1) return 0;
int res = 0;
int num = recursion(N - 1, k / 2);
if(k % 2 == 0){
if(num == 1) res = 1;
else res = 0;
}else{
if(num == 1) res = 0;
else res = 1;
}
return res;
}
}