1. 程式人生 > >面試題:最小數字

面試題:最小數字

本題來自@陳利人  微信公眾賬戶:待字閨中

原題

對於一個n位正整數a,去掉其中任意k(k<=n)個數字後,剩下的數字按原次序排列可以組成一個新的正整數。設計一個刪除演算法,使得剩下的數字組成的正整數最小。
例如,a=13243221,k=5,輸出:121

對於題目中的例子,數字13243221,刪除5個數字之後,使得剩下的幾個數字組成的整數最小。先考慮簡單的解決辦法:

當k=1時,如果要刪除13243221中的一個數字使得剩下的幾個數字組成的整數最小,很顯然,應該刪除第二位數字3,這樣剩下的整數為1243321

對於1243321整數1243321,當k=1時,要使剩下的整數最小,那麼應該刪除數字4,這樣剩下的整數為123321

對於整數123321,當k=1時,要使剩下的整數最小,那麼應該刪除一個數字3,剩下的整數為12321

從上面的分析可以發現,對於k=1,如果所給定的整數的數字從左到右時升序,那麼應該刪除最右邊的一個數,剩下的數字組成的整數最小,如果所給定的整數的數字從左到右為降序,那麼應該刪除最左邊的數字使得剩下的數字所組成的整數最小。例如k=1時,整數123,應該刪除最右邊的3,所得的整數最小,又如k=1時,整數321,那麼應該刪除最左邊的3,所得的整數最小。

那麼k>1時,只需重複上面的步驟,直至k=0。

所以,對於整數a,刪除k個數字後使所得整數最小的演算法如下:

1.從左到右掃描整數a,比較相鄰的位的數字a[i]與a[i+1]的大小;

2.若a[i] < a[i+1],那麼i++,直到a[i] >= a[i+1]或者到達整數最右邊;

3.刪除a[i],k--,若k > 0則重複步驟1。

對應演算法如下:


void deleteNum(char *input, int k) {
    int len, i;
    len = strlen(input);
    if(k > len) {
        printf("error:K > strlen(input)\n");
        return;
    }
    while(k > 0) {
        for(i = 0; i < len-1; i++){
            if(input[i] > input[i+1])
                break;
        }
        for(; i < len; i++) {
            input[i] = input[i+1];
        }
        k--;
        len--;
    }
}
但是上面的演算法有個問題,當刪除a[i]之後,右從數字的最左邊開始掃描,時間複雜度為O(n * k),這樣效率會比較低,如果可以考慮再刪除a[i]之後,繼續從a[i]開始比較,這樣效能會提升很多。再刪除a[i]之後,此時已知前面的i-1個數都小於刪除的數字a[i],那麼將刪除數字a[i]之後的整數中此時的數字a[i](刪除之前為a[i+1])與a[i-1]比較,若此時a[i] >a[i-1],則繼續向右移動,如果此時a[i] < a[i-1],則應該向左移動,刪除a[i-1]。這樣就利用了已經比較過的資訊對上面的演算法進行優化,優化後的演算法實現如下:
void deleteNumOptimized(char *input, int k) {
    int len, i, j;
    len = strlen(input);
    if(k > len)
    {
        printf("error\n");
        return;
    }
    i = 0;
    while(k > 0) {
        if(i == 0 || input[i] < input[i+1]){
             while(i < len-1 && input[i] < input[i+1]) {
                i++;
            }   
        } else {
            while(i >0 && input[i] < input[i-1]) {
                i--;
            }
        }
        for(j = i; j < len; j++) {
            input[j] = input[j+1];
        }
        k--;
        len--;

    }
}
這題屬於比較簡單的題型,從這個題中可以看出多應用已經得到的資訊,可以對演算法進行優化。

在面試筆試過程中,寫程式碼要先判斷數字的長度是否小於k值,這個細節也比較重要。