一道算法面试题
编程:数值增殖,给一个数字比如 4,增殖一次成 1 2 3 4,再增殖一次就是按照每个数字,再拓展成 1 到 X 的数列( 1 1 2 1 2 3 1 2 3 4 ),然后问第 K 次形成的序列里第 P 位是多少?
编程:数值增殖,给一个数字比如 4,增殖一次成 1 2 3 4,再增殖一次就是按照每个数字,再拓展成 1 到 X 的数列( 1 1 2 1 2 3 1 2 3 4 ),然后问第 K 次形成的序列里第 P 位是多少?
2. f 的动态规划方程可以这样:
f ( x,k )= f ( 1,k – 1 )+ f ( 2,k -1 )+ … f ( x – 1,k – 1 )
f ( x-1,k )= f ( 1,k-1 )+ … f ( x-1,k-1 )
所以有 f ( x,k )= f ( x-1,k )+ f ( x,k-1 )
计算出来的复杂度是 O ( xk ),这是预处理的过程。
3. 假设需要查询位置 p,令 g ( x,k,p )为题目所求,即变化后的数列的第 p 项,这个时候遍历 f ( 1,k-1 ),f ( 2,k-1 )… f ( x,k-1 )并维护当前数列的长度(也就是 sum )
找到 p 所在的位置 t,假设前面长度为 sum,则问题可以直接规约到 g ( t,k-1,p – sum )
这一步的时间复杂度是 O ( x )
4. 不断递降可以将 k 降低到 1,一共需要 k 次,因此总复杂度是 O ( xk )
5. 对于 k 为 1 的情况,结果是显然的。
6. 第三步的复杂度可以进一步降低,通过预处理求出 f 数列前缀和,那么可以进行二分查找找到第一个大于 p 的一项,降低为 logx
迭代 K 次可以看成形成 K 块,每块的长度为 i(1,2,3,4,5,….n), 因为前 i+1 块的和肯定是大于前 i 块的和的,也就是说是单调递增的,二分出是属于哪一块。最后在这一块里进行二分找出那一位数字就可以了。
简单就是:将找 112123123412345…的第 P 位转化为找 1234567891011…的第 P 位。
复杂度就是:O(logn * logn)
https://paste.ubuntu.com/p/fN8FkhWkbJ/
目测可以用数学归纳法证明,不过结论还是靠观察猜出来的。
如果是递推的话, 对 K 是 1,2,3 的情况计算出公式后, 结合递推式, 熟悉组合数的性质的话也能直接就能看出长度公式
这题写几个例子就很容易想到第 k 层的长度是第 k-1 层元素的和,那么就可以用前缀和算出第 k 层的 p 位是第 k-1 层的哪一位(假设为 p_{k-1})扩展而来并且可知是 p_{k-1}扩展后的第几位。接下来问题就是第 k-1 层的第 p_{k-1}位是什么,以此类推。
而求每一层的分块长度就是基本的二维 DP,第 k 层的元素可以分成第 1 层(第一次增殖后)中元素( 1,2,3…n )分别增殖 k-1 次而来,因此 k 层 i 块长度就是 sum(dp[k-1][0], dp[k-1][1],…,dp[k-1][i]),因为是前缀和所以可以简化为 sum(dp[k-1][i], dp[k][i-1])。