每日一题中一个编程题目,情景描述:一个长度为n的数组,数组由正数,0,负数组成,编写一个函数,将其重新排序为前段都是负数,0位于中间,后段均为负数的结构。要求时间复杂度为O(n)。
代码如下:
#include<iostream>
using namespace std;
//函数声明
void sort(int array[], int length);
void temp(int &a, int &b);
int main() {
int array[10] = {1,-5,6,-6,-7,8,-9,3,0,2};
sort(array,10);
for (int i = 0; i < 10; i++) {
printf("%d\t",array[i]);
}
printf("\n");
system("pause");
return 0;
}
void sort(int array[],int length) {
int head, rear,count;
head = 0;
count = 0;
rear = length - 1;
int sum=0;
for (int i = head; count < length;) {
if (array[i] > 0) {//如果第i个数大于0,就从最右边开始向左边找小于0的数
temp(array[i], array[rear]);
rear--;
count++;
}
else if (array[i] < 0) {//如果第i个数小于0,就与第head数交换,这里主要是对0后面的一些负数处理
temp(array[i],array[head]);
i++;
head++;
count++;
}
else if (array[i] == 0) {//如果第i个数等于0就跳过,0后面可能还有负数
i++;
count++;
}
sum++;
}
printf("时间复杂度为:%d\n",sum);
}
//交换ab
void temp(int &a, int &b) {
int temp;
temp = a;
a = b;
b = temp;
}
此代码复杂度为O(n),空间复杂度为O(1),此方法比较巧妙,下面是我对此方法的理解:
首先此方法有两个指针:head(头指针),rear(尾指针),head初始化为0,rear初始化为length-1;
①如果数组中第i个数大于0时,就把第i个数与第rear个数交换,temp(array[i],array[rear]),如果从rear处交换来的数字大于0,将会一直交换,直到交换来的数为负数或0时i才向后移动(此方法在做把负数向前面放,把正数往后面放);
②如果数组中第i个数为0时,i向后移动,这时head不移动,head指向的是为0;
③如果数组中第i个数小于0时,把i与head交换,temp(array[i],array[head]),然后i和head都向右移,这个交换主要是在处理当碰到0后交换,在碰到0之前,head一直都是等于i的,
对于count,它是用于控制循环次数的,无论是小于0,大于0,等于0count都要自加,严格控制循环次为n