找出3的最大倍數的整數集合

題目描述:給一個包含非負整數的數組(長度爲n),找出由這些數字組成的最大的3的倍數,沒有的話則輸出impossible。例如,如果輸入的數組爲{8,1,9},輸出應爲“9 8 1”,並且如果輸入的數組爲{8,1,7,6,0},輸出應爲”8760″。

方法一 :暴力
直接用蠻力的話,生成所有的組合,爲 2n 個,對每個數字再進行比較判斷,需要 O(n) 的時間,因爲n可能會比較大,需要每個位的比較。
總的時間複雜度爲O(n2n) .

:
可以藉助O(n)的額外空間有效的解決這個問題。該方法是基於對數以下的簡單性質:

  • 1)一個數是3的倍數,則該數字各位總和爲3的倍數。例如,讓我們考慮8760,它是3的倍數,因爲數字總和爲8 + 7 + 6 + 0 = 21,這是3的倍數。
  • 2)如果一個數是3的倍數,那麼它的所有排列也爲3的倍數,例如,6078是3的倍數,數字8760,7608,7068,…也爲3的倍數。
  • 3)一個數的所有位之和與該數會有相同的餘數。例如,如果對於151和它的各位之和7,對於3的餘數都爲1。

我們可以用下面的算法:

  • 1.對數組進行非遞減排序。
  • 2.用3個隊列 queue0,queue1,queue2,分別存儲除以3餘數爲 0、1、2的數字。
  • 3.求得所有的爲的總和sum
  • 4.有下面三種情況:
    • a) sum除以3餘0。出列的所有三個隊列中的數字,以非遞減順序排序輸出到結果數組中。
    • b) sum除以3餘1。則嘗試從queue1中移除一個元素或從queue2中移除兩個元素,如果不可以的話,則說明impossible
    • c) sum除以3餘2。則嘗試從queue1中移除兩個元素或從queue2中移除一個元素,如果不可以的話,則說明impossible
  • 5.最後將3個隊列中的所有元素都輸出到結果數組中,非遞減排序,即爲最終結果。

下面是C語言實現代碼:

#include <stdio.h>
#include <stdlib.h>

// 自定義隊列節點
typedef struct Queue
{
    int front;
    int rear;
    int capacity;
    int* array;
} Queue;

//創建一個隊列
Queue* createQueue( int capacity )
{
    Queue* queue = (Queue *) malloc (sizeof(Queue));
    queue->capacity = capacity;
    queue->front = queue->rear = -1;
    queue->array = (int *) malloc (queue->capacity * sizeof(int));
    return queue;
}

// 檢測隊列是否爲空
int isEmpty (Queue* queue)
{
    return queue->front == -1;
}

//想隊列添加一個元素
void Enqueue (Queue* queue, int item)
{
    queue->array[ ++queue->rear ] = item;
    if ( isEmpty(queue) )
        ++queue->front;
}

// 從隊列刪除一個元素
int Dequeue (Queue* queue)
{
    int item = queue->array[ queue->front ];
    if( queue->front == queue->rear )
        queue->front = queue->rear = -1;
    else
        queue->front++;

    return item;
}

// 打印數組
void printArr (int* arr, int size)
{
    int i;
    for (i = 0; i< size; ++i)
        printf ("%d ", arr[i]);
}

int compareAsc( const void* a, const void* b )
{
    return *(int*)a > *(int*)b;
}
int compareDesc( const void* a, const void* b )
{
    return *(int*)a < *(int*)b;
}

// 將3個隊列中的元素輸出到輔助數組
void populateAux (int* aux, Queue* queue0, Queue* queue1,
                            Queue* queue2, int* top )
{
    while ( !isEmpty(queue0) )
        aux[ (*top)++ ] = Dequeue( queue0 );

    while ( !isEmpty(queue1) )
        aux[ (*top)++ ] = Dequeue( queue1 );

    while ( !isEmpty(queue2) )
        aux[ (*top)++ ] = Dequeue( queue2 );
}

int findMaxMultupleOf3( int* arr, int size )
{
    // 第1步,排序
    qsort( arr, size, sizeof( int ), compareAsc );

    Queue* queue0 = createQueue( size );
    Queue* queue1 = createQueue( size );
    Queue* queue2 = createQueue( size );

    // 第2,3步
    int i, sum;
    for ( i = 0, sum = 0; i < size; ++i )
    {
        sum += arr[i];
        if ( (arr[i] % 3) == 0 )
            Enqueue( queue0, arr[i] );
        else if ( (arr[i] % 3) == 1 )
            Enqueue( queue1, arr[i] );
        else
            Enqueue( queue2, arr[i] );
    }

    //第四部,b)
    if ( (sum % 3) == 1 )
    {
        if ( !isEmpty( queue1 ) )
            Dequeue( queue1 );
        else
        {
            if ( !isEmpty( queue2 ) )
                Dequeue( queue2 );
            else
                return 0;
            if ( !isEmpty( queue2 ) )
                Dequeue( queue2 );
            else
                return 0;
        }
    }

    // 第4步,c)
    else if ((sum % 3) == 2)
    {
        if ( !isEmpty( queue2 ) )
            Dequeue( queue2 );
        else
        {
            if ( !isEmpty( queue1 ) )
                Dequeue( queue1 );
            else
                return 0;
            if ( !isEmpty( queue1 ) )
                Dequeue( queue1 );
            else
                return 0;
        }
    }

    int aux[size], top = 0;

    // 第5步
    populateAux (aux, queue0, queue1, queue2, &top);
    qsort (aux, top, sizeof( int ), compareDesc);

    // 打印結果
    printArr (aux, top);

    return 1;
}

// 測試
int main()
{
    int arr[] = {8, 1, 7, 6, 0};
    int size = sizeof(arr)/sizeof(arr[0]);

    if (findMaxMultupleOf3( arr, size ) == 0)
        printf( "Not Possible" );

    return 0;
}

關於程序算法藝術與實踐更多討論與交流,敬請關注本博客和新浪微博songzi_tea.

發佈了415 篇原創文章 · 獲贊 219 · 訪問量 180萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章