劍指OFFER之調整數組順序使奇數位於偶數前面找(九度OJ1516)


題目描述:

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有的奇數位於數組的前半部分,所有的偶數位於位於數組的后半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

 

輸入:

每個輸入文件包含一組測試案例。
對於每個測試案例,第一行輸入一個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
****************************************************************/

 

 
         


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM