我正在进行算法练习,要求重新排列整数数组,将所有偶数元素放在奇值元素之前。
我想了一会儿,想出了以下伪代码:
int[] Rearrange(int [] arr)
{
if arr.length=1
return arr;
if arr[0] is even
return arr[0] followed by Rearrange(arr.subarray(1,arr.length))
else
return Rearrange(arr.subarray(1,arr.length)) followed by arr[0]
}
我有点担心上面提出的解决方案,因为我需要在每个递归周期中进行复制操作,这很昂贵。请专家建议,谢谢!
答案 0 :(得分:1)
递归是昂贵的,你的方法会产生大量的额外副本。有时递归会产生一个优雅的解决方案,有时它绝对是错误的工具。这是一个错误的工具 - 工作案例。
相反,编写一个保持头索引和尾索引的方法。将头指针初始化为数组的开头,将尾索引初始化为结尾。
在每次传递时,循环遍历列表头部的项目,寻找奇数值。当你找到一个,停下来,然后从末尾寻找一个偶数值,向后看。找到一个时,切换两个值(使用第三个int作为临时存储。)重复一次。当头尾指数相遇时,你就完成了。
这样的事情:
int head_index = 0;
int tail_index = array.count;
int temp;
while (true)
{
//Find the next odd number at the front of the array.
while (array[head_index] %2==0) && head_index < tail_index)
head_index++;
//Find the next even number at the end of the array.
while (array[tail_index]%2==1 && head_index < tail_index)
tail_index--;
//If the pointers meet, we're done
if (head_index <= tail_index)
break;
//Swap the items at the current indexes
temp = array[head_index];
array[head_index] = array[tail_index];
array[tail_index] = temp;
}
(完全未经测试,我累了,但基本想法应该有效)
它或多或少的C语法伪代码。
它应该在O(n)时间内运行,只需要额外的RAM作为你的2个索引和临时保持变量。
答案 1 :(得分:0)
即使回答了这个问题,我也会在这里提出解决这个问题的递归版本,以便那些想知道的人可以看到为什么递归对于这个问题来说是一个糟糕的方法。
public static int[] segregate(int[] array, int left) {
int leftIndex = left;
if(left == array.length) {
return array;
}
for(int i = leftIndex + 1; i < array.length; i++) {
if(array[leftIndex] % 2 == 1) {
if(array[i] % 2 == 0) {
int temp = array[leftIndex];
array[leftIndex] = array[i];
array[i] = temp;
}
}
}
return segregate(array, leftIndex + 1);
}
从代码中可以看出,该方法将自己调用N次。当您考虑到方法中for循环的复杂性为O(N)这一事实时,递归的总复杂度将为O(n * 2),这比非递归解决方案更糟糕。