拼多多笔试第三题(AB字符串排列组合)
事先说明,本人并未参加拼多多笔试,只是听室友参加了的感觉很难,我对第三题有点感兴趣。
这里我尝试给出第三题的一点想法,希望和牛友们探讨一下~
题目:给定m,n . 最多由m个a,n个b组成一个字符串,求所有字符串中排序为K的那个字符串。
我的思路是,这道题等价于构造一个二叉前缀树(并不需要真的构造,只是方便说明),左孩子就是添加A字母,右孩子就是添加B字母,而每个节点代表的串就是它从根结点(null)到本节点的路径。
那么按照字典序排列,就是给树上的节点编号,其实等价于前序遍历给所有节点编号。
好,那么问题就在于如何确定编号了!
- 对根结点,编号是0,根结点表示空字符串。
- 对根节点的左节点,编号是1,这个也没有问题。
- 关键在于对根结点的右节点怎么编号。
如果要知道右节点编号,我们必须知道左子树的大小,所以问题在于求树的大小。
树的大小其实就是指“最多n个A字符,最多m个B字符,最多能够组成几种串”,这个定义为count[n][m]。
其实可以用dp的思路解决。
状态转移方程:树大小=1*根节点+左子树大小+右子树大小。
其实就是count[n][m] = 1 + count[n - 1][m] + count[n][m - 1]。
dp过程是O(nm)的复杂度。
好了,现在求出了子树大小,就可以开始算K下标对应的节点了。
很简单,从根结点开始找,结果字符串为空;
如果左子树的大小比当前节点下标和K的差还大,那么就在左子树找,此时结果字符串添加A字符;
否则,在右子树找,此时结果字符串添加B字符。
这样应该是O(lg K)的时间复杂度(二叉搜索树的查找)。
所以总体时间复杂度为O(mn+lg K),且空间复杂度为O(mn)。按理说是不会超时和超空间的吧(逃
代码不一定对,下面的table就是count数组,记录有n个A字符和m个B字符对应的树的size。
// Get the Kth string of the list of alphabetic order of strings, each containing at most n 'A's and m 'B's.
// 1 <= m, n <= 50
// K is a number in long
#include <iostream>
using namespace std;
// My idea: think of this permutation list as a tree.
// where alphabetic order means pre-order traversal order.
// The tree goes like this, with each node represents a string
// (the path from root to this node, e.g., the node indexed 2 stands for 'AA'):
/*
null(0)
/ \
'A'(1) 'B'(...)
/ \ \ \
'A'(2)'B'(...)... ...
*/
// The size of left subtreee could be calculated using dp, which is O(mn) time complexity,
// with transfer equation: count[n, m] = 1 + count[n - 1, m] + count[n, m - 1];
// and then we calculate the node whose index is K, which is O(lg K).
int table[51][51];
void dp(int n, int m) {
for (int i = 0; i <= n; i++)
table[i][0] = i + 1;
for (int i = 0; i <= m; i++)
table[0][i] = i + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
table[i][j] = table[i][j - 1] + table[i - 1][j] + 1;
}
int main() {
int n, m;
long long k, curr = 0;
string res;
cin >> n >> m >> k;
dp(n, m);
while (curr < k) {
if ((n > 0 && table[n - 1][m] + curr < k) || n < 1) {
// choose B
if (n > 0)
curr += table[n - 1][m] + 1;
else
curr += 1;
res += 'B';
m--;
} else {
// choose A
curr += 1;
res += 'A';
n--;
}
}
cout << res << endl;
return 0;
} #笔试题目##拼多多##校招#