LeetCode 5600. 第 K 条最小指令
1、问题描述
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 条最小指令 。
示例 1:
输入:destination = [2,3], k = 1
输出:"HHHVV"
解释:能前往 (2, 3) 的所有导航指令 按字典序排列后 如下所示:
["HHHVV", "HHVHV", "HHVVH", "HVHHV", "HVHVH", "HVVHH", "VHHHV", "VHHVH", "VHVHH", "VVHHH"].
示例 2:
输入:destination = [2,3], k = 2
输出:"HHVHV"
示例 3:
输入:destination = [2,3], k = 3
输出:"HHVVH"
2、思路与方法
问题描述地比较复杂,其实比较容易发现我们从起点到终点共需要往下走d[0]次,我们记为v,往右走d[1]次,记为h,即字符串会包括v个’V’以及h个’H’,在他们的排列组合中,找到字典序为k的字符串。这里对我来说比较好想到的方法应该是二分法,可以看下图:以v=2,h=2,k=4为例

共有6种情况,我们需要的结果是VHHV,怎么得到呢?可以看出字符串的字典序是按照一定比例关系排列的,例如第一步,h:v = 1:1,那么前三个以H开头,后三个以V开头,因为h和v的数量一致,包含h的那一半必然在前面,我们记录好[1,6],边界线为4,此时需要取出的k为4,显然第一个字符就为’V’。第二步也类似,现在h:v = 2:1,也就是说前2/3为h,后1/3为v,同样记录好[4,6],边界线为[6],此时取4则取’H’,后面几步也类似,根据这个比例关系则可以一步步得到最终结果:VHHV。
这是一个比较容易理解的思路,但是在本题中多次使用除法会导致超时(我猜),因此我们不能用除法来确定边界,需要直接获得。考虑第一步,记录为[1,6],怎么确定边界4?其实可以发现,只要求出取出H之后,字符串的组合数,便可以找到边界,我们取出一个H后,还剩一个H和两个V,因此组合数为C(3,1) = 3,由此可知边界为 1+3=4。
计算组合数花费的时间更多,但是其实组合数的计算是一个递归的过程(搜的),因此可以在计算C(4,2)的时候,用数据记录其所有包含的组合数,需要的时候取出即可。
代码:
class Solution {
int[][] dp = new int[40][40];//记录组合数
public String kthSmallestPath(int[] destination, int k) {
StringBuilder res = new StringBuilder("");
int v = destination[0];
int h = destination[1];
int left = 1;
int right = f((v+h),h);//二分法的left和right指针
for(int i = 0;i<destination[0]+destination[1];++i) {
if(h == 0) {
res.append('V');
--v;
continue;
}
if(v == 0) {
res.append('H');
--h;
continue;
}
int pos = left+dp[h+v-1][h-1];
if(k < pos) {
res.append('H');
right = pos-1;
--h;
} else {
res.append('V');
left = pos;
--v;
}
}
return res.toString();
}
private int f(int n, int k) {
if(k==0||k==n) {
dp[n][k] = 1;
return 1;
}
if(dp[n][k] == 0)
dp[n][k] = f(n-1, k)+f(n-1, k-1);
return dp[n][k];
}
}
4、复杂度
时间复杂度:算法的效率还行,3ms,不包括组合数的计算的话复杂度为O(n)
空间复杂度:需要用一个二维数组记录,不过本题范围很小,可以看作常数量级或者O(n2)
LeetCode 5600题第K条最小指令解法
博客围绕LeetCode 5600. 第K条最小指令展开。问题是在包含v个‘V’和h个‘H’的排列组合中,找字典序为k的字符串。提出二分法思路,但多次用除法会超时,需直接确定边界,通过计算组合数实现,还可记录组合数以提高效率,最后分析了复杂度。
784

被折叠的 条评论
为什么被折叠?



