题目描述
Bob 站在单元格 (0, 0)
,想要前往目的地 destination
:(row, column)
。他只能向 右 或向 下 走。你可以为 Bob 提供导航 指令 来帮助他到达目的地 destination
。
指令 用字符串表示,其中每个字符:
'H'
,意味着水平向右移动'V'
,意味着竖直向下移动
能够为 Bob 导航到目的地 destination
的指令可以有多种,例如,如果目的地 destination
是 (2, 3)
,"HHHVV"
和 "HVHVH"
都是有效 指令。
然而,Bob 很挑剔。因为他的幸运数字是 k
,他想要遵循 按字典序排列后的第 k
条最小指令 的导航前往目的地 destination
。k
的编号 从 1
开始。
给定一个整数数组 destination
和一个整数 k
,请你返回可以为 Bob 提供前往目的地 destination
导航的 按字典序排列后的第 k
条最小指令。
样例
输入:destination = [2,3], k = 1
输出:"HHHVV"
解释:能前往 (2, 3) 的所有导航指令 按字典序排列后 如下所示:
["HHHVV", "HHVHV", "HHVVH", "HVHHV", "HVHVH",
"HVVHH", "VHHHV", "VHHVH", "VHVHH", "VVHHH"]。
输入:destination = [2,3], k = 2
输出:"HHVHV"
输入:destination = [2,3], k = 3
输出:"HHVVH"
限制
destination.length == 2
1 <= row, column <= 15
1 <= k <= nCr(row + column, row)
,其中nCr(a, b)
表示组合数,即从a
个物品中选b
个物品的不同方案数。
算法
(二叉查询) $O(r + c)$
- 将
H
看做 0,V
看做 1,题目要求的就是字典序第k
个01
串。 - 从高位开始往低位确定数字
- 如果
0
的剩余个数为 0,则只能填1
。 - 否则,计算出这一位如果填 0 后,后续共有多少种可能(通过公式 $ {i - 1} \choose {zero - 1}$ 求出),记为
x
- 如果
k > x
,则说明这一位不应该填0
,需要填1
,同时k
应该减去x
。 - 否则,这一位填
0
。
- 如果
- 如果
- 可以预处理组合数数组避免整数计算溢出。
时间复杂度
- 共遍历 $r + c$ 次,每一次仅需要判断组合数,故总时间复杂度为 $O(r + c)$。
空间复杂度
- 仅需要 $O(r + c)$ 的空间存储预处理的组合数数组。
C++ 代码
class Solution {
public:
string kthSmallestPath(vector<int>& destination, int k) {
int zero = destination[1], one = destination[0];
const int n = zero + one;
vector<vector<int>> C(n + 1, vector<int>(n + 1));
C[0][0] = 1;
for (int i = 1; i <= zero + one; i++) {
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
string ans;
for (int i = n; i >= 1; i--) {
if (zero == 0) ans += "V";
else {
if (k > C[i - 1][zero - 1]) {
k -= C[i - 1][zero - 1];
ans += "V";
one--;
} else {
ans += "H";
zero--;
}
}
}
return ans;
}
};
这题是不是和数位dp有点类似
今天补了这道题,发现可以用数轴帮助理解。
1. 首先我们要知道,第1个序列是(H…)(V…)。因此,只要前面全是H,那么当前序列是第几个序列由后面的组合决定。
2. 假设现在剩余 n 个位置,其中 h 个 ‘H’ ,并且有M种可能性,那么第一个位置选 ‘H’ 的组合数是 C(n - 1, h - 1)。
3. 引入一条数轴,有3个点:1、C(n - 1, h - 1)、M。
4. 如果1 <= k <= C(n - 1, h - 1),说明第k个序列是第一个位置选 ‘H’ 后,剩余n - 1个位置的第 k 个组合。
5. 如果 C(n - 1, h - 1) < k <= M,说明第k个序列在第一个位置选 ‘V’ 的组合中,它是剩余n - 1个位置的第 k - C(n - 1, h - 1)个组合。
上面的话,自己画数轴就很好理解了。
补充,k在C(n - 1, h - 1)前后分别代表第k个序列出现在选H或V的组合中。
自己做的时候,没有找出两段性,还是抽象问题能力8够强,多做应该会好起来8。冲冲冲
请问这道题的知识点是 :组合计数 + 递推 吗?
这里涉及到数学的东西很简单,但通过二叉的方式找第
k
小的思想是应该学习的,类似于二叉查找树。感觉有点类似快速排序的partition找第k小的数。
这里二分和组合计数结合的套路,是我第一次见。。。
学到东西了哈哈。