2016阿里笔试题:一个最小数,一个最大数地,重排数组
@(algorithm)
问题描述
2017阿里笔试题
原始数组是排好序的,如:[0,1,2,3,4,5,6]
结果数组是一个最小数,一个最大数地重排数组。即:[0,6,1,5,2,4,3]
要求使用O(1)的空间复杂度,O(n)的时间复杂度。
参考
virtual index:
https://discuss.leetcode.com/topic/32929/o-n-o-1-after-median-virtual-indexing/2
分析
首先分析初始数组的下标与结果数组的下标的关系:
ori | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
dst | 0 | 2 | 4 | 6 | 5 | 3 | 1 |
很明显,当原始下标ori <= (len - 1) / 2
的时候dst = ori * 2
:
ori | 0 | 1 | 2 | 3 |
---|---|---|---|---|
dst | 0 | 2 | 4 | 6 |
否则:
ori | 4 | 5 | 6 |
---|---|---|---|
dst | 5 | 3 | 1 |
这个关系似乎不太容易看得出来,可以用dst = a * ori + b
拟合
得到dst = -2 * ori + 13
,再猜一下13与len=7有关,应该是13 = len * 2 - 1
即:dst = -2 * ori + 2 * len - 1
然后就可以根据这个映射写出映射函数了。
最后利用迭代,把数组的元素依次替换。
代码
#include <iostream>
using namespace std;
int findIndex(int ori, int len)
{
if (ori <= (len - 1) / 2)
{
return ori * 2;
}
else
{
return -2 * ori + 2 * len - 1;
}
}
void print(int* a, int len)
{
for (int i = 0; i < len; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
void printNewIndex(int* a, int len)
{
for (int i = 0; i < len; i++)
{
cout << findIndex(i, len) << " ";
}
cout << endl;
}
void shuffle(int *a, int len)
{
// 2个元素以下的数组无需调整
if (len <= 2)
return;
// 当前位置
int nowpos = 1;
// 下一个位置
int nextpos = findIndex(nowpos, len);
// 记录下一个位置的值
int tmp = a[nextpos];
// 更改下一个位置的值为当前位置的值
a[nextpos] = a[nowpos];
for (int i = 2; i < len; i++)// 循环len-2次
{
nowpos = nextpos;// 当前位置是上一个的nextpos
nextpos = findIndex(nowpos, len);// 使用函数查找下一个位置
swap(tmp, a[nextpos]);// 交换下一个位置的值和tmp
}
}
int main(int argc, const char * argv[])
{
// insert code here...
int a[7] = {1,3,5,7,9,11,13};
int len = 7;
cout << "原始数组:\n";
print(a, len);
cout << "变换后的index:\n";
printNewIndex(a, len);
cout << "变换后的数组:\n";
shuffle(a, len);
print(a, len);
return 0;
}