力扣 779 第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.由观察可得:
第一行: 0
第二行: 01
第三行: 0110
第四行: 01101001
第五行:0110100110010110
每行前半部分与上一行相同,后半部分为上一行取反
则可进行分类讨论,若K在前半部分则对应上一行元素,进行递归即可,若K在后半部分则对应取反即可。

int k_n(int N,int K)
{
    int p;//前一行长度,每行长度为2^(N-1)
    if(N==1)
        return 0;
    if(N==2)
    {
        return K==1?0:1;
    }
    p=(pow(2,N-1))/2;
    if(K<=p)
    {
        return k_n(N-1,K);
    }
    else{
        return 1-k_n(N-1,K-p);//非0即1
    }

}

int main()
{
    int N,K;
    scanf("%d %d",&N,&K);

    printf("%d",k_n(N,K));
    return 0;
}

其中求p也可用位运算,用左移运算符:
p=(1<<(N-1))/2;
或1<<(N-2)
例若N=2,(N-1)=1,二进制为0001,向左移一位变为,0010,为2。

2.也可采用尾递归:

int kthGrammar(int N, int K)
{
	if (N == 1) return 0;
	return (kthGrammar(N - 1, (K - 1) / 2 + 1) == 0) ? ((K - 1) % 2) : 1 - ((K - 1) % 2);
	//这一步做了3种多步判断,高度精简
}

其中 return (kthGrammar(N - 1, (K - 1) / 2 + 1) == 0) ? ((K - 1) % 2) : 1 - ((K - 1) % 2); 很妙,高度精简,灵活运用三元运算符

(kthGrammar(N - 1, (K - 1) / 2 + 1) == 0) 为真,执行((K - 1) % 2),为假则执行1 - ((K - 1) % 2)
==(kthGrammar(N - 1, (K - 1) / 2 + 1) == 0)==递归,其为真即N行K的父节点为0,(K - 1) / 2 + 1)为0,
执行((K - 1) % 2),此时需左(奇)为0,右(偶)为1,当K是偶数时,((K - 1) % 2)为1,若用(K%2)则相反,
为假(即父节点为1)则执行 1 - ((K - 1) % 2),这里可用(K%2)

3.与2想法类似,构造二叉树,
生成规则可以认为是一棵二叉树,找到当前节点对应的父节点即可判断出当前节点值。

由于下标是从1开始,所以N层第k个节点的父节点是N-1层第(k+1)/2个节点。(对其进行递归)(K,N均为整数,则不需判断是奇数或偶数)

如果k是偶数,表明是右子树,奇数为左子树。(求得N-1层的结点若其为1,则左1,右0,若K是偶数,则在右为0,也即为右子树)

int k_n(int N,int K)
{
    int pro;
    if(N==1)
        return 0;
    pro=k_n(N-1,(K+1)/2);//也可用(K+1)>>1
    if(pro==1)
    {
        return K%2==0?0:1;
    }
    else
        return K%2==0?1:0;
}

递归还需深入学习。
这几种方法都源于一种思想,观察
两种想法,一,取反,二,由K向上推导。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值