拼多多校招笔试算法题:一行公式搞定“多多的魔术盒子”
By Long Luo
众多IT大厂中拼多多虽然工作强度很大,但在给钱方面非常大方。大厂给的钱多,但要求也高。下面就来挑战拼多多 2020 年校招笔试算法题 1 中第一题:多多的魔术盒子 2 ,看看难度如何。
多多的魔术盒子
多多鸡有 \(N\) 个魔术盒子(编号 \(1 \sim N\) ),其中编号为 \(i\) 的盒子里有 \(i\) 个球。多多鸡让皮皮虾每次选择一个数字 \(X\) ( \(1 \le X \le N\) ),多多鸡就会把球数量大于等于 \(X\) 个的盒子里的球减少 \(X\) 个。 通过观察,皮皮虾已经掌握了其中的奥秘,并且发现只要通过一定的操作顺序,可以用最少的次数将所有盒子里的球变没。
那么请问聪明的你,是否已经知道了应该如何操作呢?
时间限制:
- C/C++ 1秒,其他语言 2 秒
空间限制:
- C/C++ 256M,其他语言 512M
输入描述:
- 第一行,有 \(1\) 个整数 \(T\) ,表示测试用例的组数。 ( \(1 \le T \le 100\) )
- 接下来 \(T\) 行,每行 \(1\) 个整数 \(N\) ,表示有 \(N\) 个魔术盒子。 ( \(1 \le N \le 1,000,000,000\) )
输出描述:
- 共 \(T\) 行,每行 \(1\) 个整数,表示要将所有盒子的球变没,最少需要进行多少次操作。
输入例子 1 :
1
2
3
43
1
2
5输出例子 1 :
1
2
31
2
3
最少的操作次数该怎么做?
根据题意,我们关键是要找到最少次数这个方法,那如何操作才能使用最少次数呢?
当面对复杂问题时,我们需要从简单情况入手,分析其中规律,找到突破口。
- \(N = 1\) 时,显然选择 \(X = 1\) ,需要 \(1\) 次操作;
- \(N = 2\) 时,可以先选择 \(X = 1\) ,再选择 \(X = 2\) ,需要 \(2\) 次操作;
- \(N = 3\) 时,只有先选择 \(X = 2\) ,再选择 \(X = 1\) ,最少需要 \(2\) 次操作;
- \(N = 4\) 时,可以先选择 \(X = 2\) 或者 \(X = 3\) ,最少需要 \(3\) 次操作;
通过分析发现,每次操作之后,球的数量都会动态变化。如果每次都选择中间的数字,这样每次操作之后,如果 \(N\) 为奇数的话,可以变成 \(2\) 个对称相同的数组, \(N\) 为偶数的话,则 \(2\) 个数组中元素值会相差 \(1\) ,再选择元素值更多的数组进行消除,这样可以实现操作次数最少。
实现代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13private static int leastTimes_power(int n) {
int ans = 1;
for (int i = 0; i <= Math.sqrt(n); i++) {
if (Math.pow(2, i) <= n) {
ans = i;
} else {
break;
}
}
return ans + 1;
}
为什么每次选取中间的数字进行操作次数最少呢?下面我们就来严谨的证明下!