題目描述:
-
輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有的奇數位於數組的前半部分,所有的偶數位於位於數組的后半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。
- 輸入:
-
每個輸入文件包含一組測試案例。
對於每個測試案例,第一行輸入一個n,代表該數組中數字的個數。
接下來的一行輸入n個整數。代表數組中的n個數。
輸出:
-
對應每個測試案例,
輸入一行n個數字,代表調整后的數組。注意,數字和數字之間用一個空格隔開,最后一個數字后面沒有空格。
- 樣例輸入:
-
5 1 2 3 4 5
- 樣例輸出:
-
1 3 5 2 4
解題思路:
- 首先,說一種時間復雜度為O(n),但是空間復雜度較高的。但是這種代碼,肯定不會是面試官喜歡的。
- 我們申請另外兩個數組,每次輸入數據時,直接比對是奇數還是偶數,順序存放在兩個數組中,並記錄下標的變化。最后兩個數組順序輸出就行了,核心代碼如下:
for(i=0;i<n;i++){ scanf("%d",&arr[i]); if(arr[i]%2 == 1){ arr1[num_arr1++] = arr[i]; }else{ arr2[num_arr2++] = arr[i]; } } for(i=0;i<num_arr1;i++){ printf("%d ",arr1[i]); } for(i=0;i<num_arr2-1;i++){ printf("%d ",arr2[i]); }
代碼:
#include <stdio.h> #include <memory.h> #define N 100000 int arr[N]; int arr1[N]; int arr2[N]; void diffoddandeven(int n); int main(void){ int n,i,num_arr1,num_arr2; while(scanf("%d",&n)!=EOF && n>0){ num_arr1 = num_arr2 = 0; memset(&arr,0,sizeof(int)*N); memset(&arr1,0,sizeof(int)*N); memset(&arr2,0,sizeof(int)*N); for(i=0;i<n;i++){ scanf("%d",&arr[i]); if(arr[i]%2 == 1){ arr1[num_arr1++] = arr[i]; }else{ arr2[num_arr2++] = arr[i]; } } for(i=0;i<num_arr1;i++){ printf("%d ",arr1[i]); } for(i=0;i<num_arr2-1;i++){ printf("%d ",arr2[i]); } printf("%d\n",arr2[num_arr2-1]); } return 0; } /************************************************************** Problem: 1516 User: xhalo Language: C Result: Accepted Time:100 ms Memory:2084 kb ****************************************************************/
第二種方法
另一種思想,不開辟新的空間,直接在原始數組上,進行移動。但是考慮到前后的順序不能變化,因此簡單的哨兵替換思想就不可以了。這時候我們可以通過兩個下標,進行數據元素的移動。
首先,考慮到奇數排在前面,偶數在后面,因此我們遍歷數組,找到第一個奇數,和第一個偶數。如果第一個奇數在偶數的后面,就替換他們的位置,及下標:
while(arr[i]%2 == 0 && i<n){ i++; flag = 1; } int j=0; while(arr[j]%2 == 1 && j<n){ j++; } if(i>j){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; temp = i; i = j; j = temp; }
此時,有種特殊的情況,就是數組元素中全是偶數,或者全是奇數,顯然就不需要進行其他的操作了。
while(arr[i]%2 == 0 && i<n){ i++; flag = 1; } int j=0; while(arr[j]%2 == 1 && j<n){ j++; } if(i==n || j == n){//新添加的代碼在這里 //printf("純\n"); return ; } if(i>j){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; temp = i; i = j; j = temp; }
然后到了關鍵的步驟,找到第一個奇數i,和第一個偶數j后,繼續尋找第二個奇數i',然后把i'到j的元素向后移,把i'放到j的位置上。模仿直接插入排序。
第一步,尋找第一個奇數和第一個偶數
然后找到第二個奇數
把奇數拿出來,i到j向后移動,再把i放回去
接着進入下一次循環,再次尋找下一個奇數和偶數
此時判斷條件退出。
while(i<n-1 && j<n-1){ i++; while(arr[i]%2 == 0 && i<n){ i++; } if(i == n){ return ; } temp = arr[i]; int k; for(k=i;k>j;k--){ arr[k] = arr[k-1]; } arr[j] = temp; while(j<n && arr[j]%2 == 1){ j++; } }
循環上面代碼,最終就會保證數據的輸出。
另外一種特殊的情況,如果數組是 1 2 3 4 5,那么我們找到第一個奇數1和第一個偶數2,這是正常現象。但是如果是1 3 5 6 7,我們找到第一個奇數1和第一個偶數6,如果繼續按照上面的代碼,i<j就會出錯。因此我們在初始時,判斷是否有連續的奇數存在,如果存在就尋找到最后一個奇數的位置。
while(arr[i]%2 == 0 && i<n){ i++; flag = 1; } if(i == 0){ //如果初始有連續的奇數存在,就尋找最后一個奇數 while(arr[i]%2 == 1 && i<n ){ i++; flag = 1; } if(flag) i--; if(arr[i]%2==0 && i==n-1) return ; } int j=0; while(arr[j]%2 == 1 && j<n){ j++; } if(i==n || j == n){ //printf("純\n"); return ; } if(i>j){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; temp = i; i = j; j = temp; }
這個算法雖然節省了空間,但是時間復雜度要求高點。AC未能通過最后一項,最后一樣測試好像是100000-40000的數據量。
代碼:
#include <stdio.h> #include <memory.h> #define N 100000 int arr[N]; void diffoddandeven(int n); int main(void){ int n,i; while(scanf("%d",&n)!=EOF && n>0){ memset(&arr,0,sizeof(int)*N); for(i=0;i<n;i++){ scanf("%d",&arr[i]); } diffoddandeven(n); for(i=0;i<n-1;i++){ printf("%d ",arr[i]); } printf("%d\n",arr[n-1]); } return 0; } void diffoddandeven(int n){ int temp; int i=0; int flag = 0; while(arr[i]%2 == 0 && i<n){ i++; flag = 1; } if(i == 0){ while(arr[i]%2 == 1 && i<n ){ i++; flag = 1; } if(flag) i--; if(arr[i]%2==0 && i==n-1) return ; } int j=0; while(arr[j]%2 == 1 && j<n){ j++; } if(i==n || j == n){ //printf("純\n"); return ; } if(i>j){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; temp = i; i = j; j = temp; } while(i<n-1 && j<n-1){ i++; while(arr[i]%2 == 0 && i<n){ i++; } if(i == n){ return ; } temp = arr[i]; int k; for(k=i;k>j;k--){ arr[k] = arr[k-1]; } arr[j] = temp; while(j<n && arr[j]%2 == 1){ j++; } } } /************************************************************** Problem: 1516 User: xhalo Language: C Result: Time Limit Exceed ****************************************************************/