题目描述:
- 构造长度为N的数组arr,此数组需要满足: 对于任意 i < k < j ,arr[i] + arr[j] != 2 * arr[k] 。
这里有个前提:
对原数组做奇变换和偶变换,也达标,可以证明的。见下面:
其实加1、加2、减100等等这种变换也能够达标,那为啥要奇偶变换呢?
因为好做啊,想象我们要扩大数组,如果我们前面拿一个达标的奇数数组,后面拿一个达标的偶数数组, (一个odd + 一个even 一定不会等于 2 * 一个num )的。所以,拼接起来的大数组一定是达标的。
代码:
/** 题目描述:
* 1. 构造长度为N的数组arr,此数组需要满足:
* 对于任意 i < k < j ,arr[i] + arr[j] != 2 * arr[k] 。
*/
#include <iostream>
#include <vector>
/** 递归构造达标的数组。
* @param n:要构造的数组的长度
* @return 一个vector
*/
std::vector<int> constructArray(int n) {
if (n <= 1) //base case
return std::vector<int>(1, 1);
int halfSize = (n + 1) >> 1;
std::vector<int> base = constructArray(halfSize); // 递归调用
std::vector<int> res(n, 0);
int index = 0;
for (; index < halfSize; ++index) {
res[index] = 2 * base[index] + 1;
}
for (int i = 0; index < n; ++index, ++i) {
res[index] = 2 * base[i];
}
return res; // 返回局部对象的拷贝,这里会发生调用原局部对象的析构,
// 以及需要调用生成临时对象的拷贝构造。
// 函数的返回不能是引用&。
}
/** 检验函数,暴力做法,判断arr是不是达标的。 */
bool isValid(const std::vector<int>& arr) { // test()函数时间主要花在这里 O(N^3)
int size = arr.size();
for (int i = 0; i < size - 2; ++i) {
for (int k = i + 1; k < size - 1; ++k) {
for (int j = k + 1; j < size; ++j) {
if (arr[i] + arr[j] == 2 * arr[k]) {
return false;
}
}
}
}
return true;
}
/** 对数器测试函数 */
void test() {
std::cout << "test begin.\n";
for (int i = 1; i < 500; ++i) {
std::vector<int> arr = constructArray(i);
if (isValid(arr)) {
std::cout << i << ":Success!\n";
}
else {
std::cout << i << ":Oops!\n";
}
}
std::cout <<"test end.\n\n";
// 单独两个test case
std::cout << isValid(constructArray(1000)) << "\n";
std::cout << isValid(constructArray(500)) << "\n";
}
以上测试肯定是能通过的。
constructArray() 函数的时间复杂度为 O(N),
递推公式为:T(N) = T(N/2) + O(N)。可以手推一下,或者直接根据Master公式就可以了。
这种重业务的题目,每次肯定都是不一样的,积累吧!或者智力很顶的人问题也不大。
纸上得来终觉浅,绝知此事要躬行。