【递归】二进制字符串中的第K位

题目描述

给你两个正整数 n 和 k,二进制字符串 Sn 的形成规则如下:

  1. S1 = “0”
  2. 当 i > 1 时,Si = Si-1 + “1” + reverse(invert(Si-1))

其中 + 表示串联操作,reverse(x) 返回反转 x 后得到的字符串,而 invert(x) 则会翻转 x 中的每一位(0 变为 1,而 1 变为 0)。
例如,符合上述描述的序列的前 4 个字符串依次是:
S1 = “0”
S2 = “011”
S3 = “0111001”
S4 = “011100110110001”
请你返回 Sn 的 第 k 位字符 ,题目数据保证 k 一定在 Sn 长度范围以内。
例如输入:n = 3, k = 1,会输出:“0”。因为S3 为 “0111001”,其第 1 位为 “0” 。

输入格式

第一行2个正整数:N K。N 范围[2, 30];

输出格式

1或0

输入/输出例子1

输入:
4 11

输出:
1

解题思路

这题的思路非常巧妙,通过观察我们知道二进制字符串Sn中间位都是1,左右两边是取反后并对称。所以,如果某一位处在后半段,我们可以找到前半段对应数位取反即可求到答案。这样我们可以把问题规模变小,当字符串长度为1或者是要求的数位处于S的中间位时我们就可以得到答案,然后结束。
因此我们可以定义递归函数,有三个组成要素,一个是字符串长度l,一个是我们要求的位k,还有一个是是否进行了取反操作rv,rv=1表示做了取反,rv=0表示没有取反。对于两个结束条件的返回值,先讨论通过若干次递归,问题规模变小,使得l=1的情况,对于这种情况如果没有取反操作的,我们观察S1可知,返回0(此时rv也是为0)。如果是后半段往前找的,就要取反,函数传的参数rv=1,返回1。归纳起来就是,如果长度为1时,返回rv。再看要求的数位处于S的中间位的情况,如果k在原字符串中本来就是处于前半段的,且折半后k在中间位就返回1。如果k在原字符串中本来就是处于后半段的,将其对应到前半段的位置l-k+1,且折半后在中间位就返回0(此时要取反)。所以返回的应该是1-rv。如果没达到结束条件,就进行折半和比较,直到到达结束条件为止。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,k;
int dg(int l,int k,int rv){
	if(l==1) return rv;
	int m=(l+1)/2;
	if(m==k) return 1-rv;
	if(m<k) dg(l/2,l-k+1,1-rv);
	else dg(l/2,k,rv);
}
int main(){
	cin>>n>>k;
	int ln=0;
	for(int i=1;i<=n;i++) ln=ln*2+1;
	cout<<dg(ln,k,0);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值