题目 第K个语法符号
在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。
给定行数 N 和序数 K,返回第 N 行中第 K个字符。(K从1开始)
示例:
输入: N = 1, K = 1
输出: 0
输入: N = 2, K = 1
输出: 0
输入: N = 2, K = 2
输出: 1
输入: N = 4, K = 5
输出: 1
解释:
第一行: 0
第二行: 01
第三行: 0110
第四行: 01101001
解1 递归
通过递归
- 首先获取N-1行的数字串str
- 遍历字符串str,并定义一个新字符串str2
当遇到0,str2添加“01”;
当遇到1,str2添加“10” - 返回str2
- 终止条件则是N=1:返回字符串“0”;
class Solution {
public:
char cK;
public:
int kthGrammar(int N, int K) {
string str;
//获取第N行的数字串
str = getChar(N);
return str[K-1]-'0';
}
string getChar(int N)
{
//如果时第1行,返回“0”
if(N == 1)
{
return "0";
}
//N>1,先获得上一行的字符串
string str = getChar(N-1);
//遍历上一行字符串,获得该行的字符串
string str2;
for(int i=0 ; i<str.length() ; i++)
{
if(str[i] == '0')
str2 += "01";
else
str2 += "10";
}
//返回本行字符串
return str2;
}
};
解2 按照规律
将每行数字按照二叉树形式划分,可以发现,根据K值:
- 若K为奇数,则对应上一行的第(K+1)/2个位置的值
- 若K为偶数,先判断K/2为的奇偶性
a. 若K/2为奇数:则对应上一行的K/2+1;
b. 若K/2为偶数:则对应上一行的K/2-1; - 向上逐层对应,直到获得第二层K值,返回K-1
class Solution {
public:
int kthGrammar(int N, int K)
{
while(N != 1)
{
//K是奇数
if(K%2 ==1)
K = (K+1)/2;
//K是偶数
else
// K/2奇偶? 奇 偶
K = (K/2%2 == 1) ? K/2+1 : K/2-1;
N--;
}
//找到对应第2行的K值,返回K-1即所求数
return K-1;
}
};
解3
如图可以发现公式
第K个值 = (K+1)%2 ⊕上一行第(K+1)/2位置的值(即上一行生成该数字的值)
故通过递归实现:
class Solution {
public:
int kthGrammar(int N, int K)
{
if(N == 1)
return 0;
return (K+1)%2^kthGrammar(N-1,(K+1)/2);
}
};
解4
查看每一行,后半部分是前半部分的翻转,且前半部分和其上一行相同。故:
- 若K的位置在前半部分,则该位置值对应上一行第K个位置的值
- 若K的位置在后半部分,则该位置对应上一行第K个位置的值的翻转。
!!注意:每一行的值的个数:2^(N-1) 故代码中的 1<<(N-2) =( 2^(N-1))/2
class Solution {
public:
int kthGrammar(int N, int K)
{
if(N == 1)
return 0;
if(K > 1<<(N-2))
return 1-kthGrammar(N-1,K-(1<<(N-2)));
else
return kthGrammar(N-1,K);
}
};