1545-找出第 N 个二进制字符串中的第 K 位

Raphael Liu Lv10

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

  • S1 = "0"
  • i > 1 时,Si = Si-1 + "1" + reverse(invert(Si-1))

其中 + 表示串联操作,reverse(x) 返回反转 x 后得到的字符串,而 invert(x) 则会翻转 x 中的每一位(0 变为
1,而 1 变为 0)。

例如,符合上述描述的序列的前 4 个字符串依次是:

  • S1 = "0"
  • S2 = "0 **1** 1"
  • S3 = "011 **1** 001"
  • S4 = "0111001 **1** 0110001"

请你返回 Snk 位字符 ,题目数据保证 k 一定在 Sn 长度范围以内。

示例 1:

**输入:** n = 3, k = 1
**输出:** "0"
**解释:** S3 为 " **0** 111001",其第 1 位为 "0" 。

示例 2:

**输入:** n = 4, k = 11
**输出:** "1"
**解释:** S4 为 "0111001101 **1** 0001",其第 11 位为 "1" 。

示例 3:

**输入:** n = 1, k = 1
**输出:** "0"

示例 4:

**输入:** n = 2, k = 3
**输出:** "1"

提示:

  • 1 <= n <= 20
  • 1 <= k <= 2n - 1

方法一:递归

观察二进制字符串 S_n,可以发现,当 n>1 时,S_n 是在 S_{n-1 的基础上形成的。用 len}n 表示 S_n 的长度,则 S_n 的前 len}{n-1 个字符与 S_{n-1 相同。还可以发现,当 n>1 时,len}n=\text{len}{n-1} \times 2 + 1,根据 len}_1=1 可知 len}_n=2^n-1。

由于 S_1=``0”,且对于任意 n \ge 1,S_n 的第 1 位字符也一定是 0',因此当 k=1 时,直接返回字符 0’。

当 n>1 时,S_n 的长度是 2^n-1。S_n 可以分成三个部分,左边 2^{n-1}-1 个字符是 S_{n-1,中间 1 个字符是 1',右边 2^{n-1}-1 个字符是 S_{n-1 翻转与反转之后的结果。中间的字符 1’ 是 S_n 的第 2^{n-1 位字符,因此如果 k=2^{n-1,直接返回字符 `1’。

当 k \ne 2^{n-1 时,考虑以下两种情况:

  • 如果 k<2^{n-1,则第 k 位字符在 S_n 的前半部分,即第 k 位字符在 S_{n-1 中,因此在 S_{n-1 中寻找第 k 位字符;

  • 如果 k>2^{n-1,则第 k 位字符在 S_n 的后半部分,由于后半部分为前半部分进行翻转与反转之后的结果,因此在前半部分寻找第 2^n-k 位字符,将其反转之后即为 S_n 的第 k 位字符。

上述过程可以通过递归实现。

[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public char findKthBit(int n, int k) {
if (k == 1) {
return '0';
}
int mid = 1 << (n - 1);
if (k == mid) {
return '1';
} else if (k < mid) {
return findKthBit(n - 1, k);
} else {
k = mid * 2 - k;
return invert(findKthBit(n - 1, k));
}
}

public char invert(char bit) {
return (char) ('0' + '1' - bit);
}
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const invert = (bit) => bit === '0' ? '1' : '0';

var findKthBit = function(n, k) {
if (k == 1) {
return '0';
}
const mid = 1 << (n - 1);
if (k == mid) {
return '1';
} else if (k < mid) {
return findKthBit(n - 1, k);
} else {
k = mid * 2 - k;
return invert(findKthBit(n - 1, k));
}
};
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
char findKthBit(int n, int k) {
if (k == 1) {
return '0';
}
int mid = 1 << (n - 1);
if (k == mid) {
return '1';
} else if (k < mid) {
return findKthBit(n - 1, k);
} else {
k = mid * 2 - k;
return invert(findKthBit(n - 1, k));
}
}

char invert(char bit) {
return (char) ('0' + '1' - bit);
}
};
[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def findKthBit(self, n: int, k: int) -> str:
if k == 1:
return "0"

mid = 1 << (n - 1)
if k == mid:
return "1"
elif k < mid:
return self.findKthBit(n - 1, k)
else:
k = mid * 2 - k
return "0" if self.findKthBit(n - 1, k) == "1" else "1"

复杂度分析

  • 时间复杂度:O(n)。字符串 S_n 的长度为 2^n-1,每次递归调用可以将查找范围缩小一半,因此时间复杂度为 O(\log 2^n)=O(n)。

  • 空间复杂度:O(n)。空间复杂度主要取决于递归调用产生的栈空间,递归调用层数不会超过 n。

 Comments
On this page
1545-找出第 N 个二进制字符串中的第 K 位