题目来源:https://leetcode.cn/problems/k-th-symbol-in-grammar/
大致题意:
题目构建了一个 n 行的表,表的第一行为 0,之后每一行的内容都由上一行的内容变化而来。变化规则为:
- 0 变为 01
- 1 变为 10
求第 n 行第 k 个元素的值
思路
根据题意,那么表的前几行为
- 0
- 01
- 0110
- 01101001
- 0110100110010110
- 01101001100101100110100110010110
- …
那么可以看出,第 i 行的第 j 个数由第 i - 1 行的第 (j + 1) / 2 个数变化而来,它们的关系有
- 第 i - 1 行的第 (j + 1) / 2 个数为 0,变化数为 01,第 i 行的第 j 个数为奇数,那么对应 01 的第 1 个值 0
- 第 i - 1 行的第 (j + 1) / 2 个数为 0,变化数为 01,第 i 行的第 j 个数为偶数,那么对应 01 的第 2 个值 1
- 第 i - 1 行的第 (j + 1) / 2 个数为 1,变化数为 10,第 i 行的第 j 个数为奇数,那么对应 01 的第 1 个值 1
- 第 i - 1 行的第 (j + 1) / 2 个数为 1,变化数为 10,第 i 行的第 j 个数为偶数,那么对应 01 的第 2 个值 0
综上可知
- 第 i - 1 行的第 (j + 1) / 2 个数的变化数为 xy,若第 i 行的第 j 个数为奇数,那么其为 x;否则,其为 y
同样,根据上面的规律可以看出第 1 个数永远为 0,那么可以逆序求出每一行的奇偶性,直至当前元素值为 1,再根据刚刚求得的奇偶性求出最终结果
具体解题流程为
- 使用 k 表示当前数为所在行第 k 个数,使用栈存储 k 大于 1 时 k 的奇偶性
- 在 k 大于 1 时执行循环,存下当前奇偶性并更新 k 的值为 (k + 1) / 2。这里表示当前行第 k 个值,由上一行第 (k + 1) / 2 值变化而来
- 初始化当前值为 0,根据奇偶性更新下一行的值,直至栈空
代码:
public int kthGrammar(int n, int k) {
// 存每一行的奇偶情况
Deque<Integer> stack = new ArrayDeque<>();
while (k > 1) {
// 偶数将 2 入栈,表示当前数是上一行对应位置变化数的第 2 个
if (k % 2 == 0) {
stack.push(2);
} else { // 奇数将 1 入栈,表示当前数是上一行对应位置变化数的第 1 个
stack.push(1);
}
// 更新索引
k = (k + 1) / 2;
}
// 取当前索引对应的数
int ans = 0;
while (!stack.isEmpty()) {
// 取出当前行标志位
int cur = stack.pop();
// 根据上一行对应位置的值,计算其变化的值
// 0 变为 01;1 变为 10
int first = ans == 0 ? 0 : 1;
int second = first == 0 ? 1 : 0;
// 如果标志位为 1,表示当前行是奇数位,为第一个值
if (cur == 1) {
ans = first;
} else { // 否则表示当前行为偶数位,为第二个值
ans = second;
}
}
return ans;
}