1. 程式人生 > >繼續貪心:刪數問題

繼續貪心:刪數問題

上次已經講過一次貪心了,這次就來個小實戰吧,下面看題:
**

刪數問題

**

已知一個數組,要求從陣列中刪除n個數,要求剩下的數按順序排列成的數字最小。例:陣列為{1,3,2,4,7,0,5} n = 3; 輸出結果為: 1 2 0 5

拿到題先分析,首先分析上面的例子試試吧,既然要刪除n個數,那就一個一個刪吧,那麼刪的時候要遵循什麼標準呢?只要每次刪的時候依次列舉刪後的結果,挑選一個最小的就好了。因為每次刪數都需要遍歷當前數組裡的有效值,需要刪n個數,所以時間複雜度大概為O(n*len);但是,我們每次刪除一個數時,都要將數組裡的有效元素一一提取出來,合併成一個整數,才可以進行比較,這個合併的過程時間複雜度為O(len);當然,你可以直接按順序從陣列頭部到尾部依次比較,這樣可以優化一些,但是無法改變本質,最壞時間複雜度依然是O(len);這種方法也很簡單,所以我就不講這個演算法了,下面提供另一種思路。
首先,我們學習貪心演算法,其實並沒有什麼用,因為大部分人即使不學貪心演算法也會有貪心的思想,而且演算法本身只是思想,空有一身思想是沒有任何用的,寫出什麼程式,完全是看自己如何思考的。
所以,我們的目的不只是如何貪心,而是如何儘可能的貪。
首先,從邏輯上講,刪數和選數是一樣的。刪n個數等價於選len-n個數。那麼我們可以將刪數轉化成選數問題。那麼我們根據什麼標準來選數呢?是每次選最小的嗎?就上面的例子說,如果要刪除五個數,那就是選擇兩個數,結果很明顯是 0 5,但是假如每次選最小的數,得到的結果是 1 0,是不正確的。所以可以排除每次選最小的方案,但是選擇小的肯定不會錯,分析發現,當第一次選擇最小的數,這個數把陣列分成兩部分,下次選擇時,只要這個最小的數後面還有數,那麼一定優先選後面的數,當後面的數選完時,才選擇前面的數。
那麼看看邏輯吧:
陣列中有len個數,需要選擇n個數,我們先選擇一個最小的,先假設這個最小的數的下標為i,那麼還需要選擇n-1個數,這n-1個數優先從最小的數的後面選,最小的數後面一共還有len-i個數,那麼就有兩種情況:
①:len-i > n-1 ;從最小的數後面的數裡選擇n-1個數;
②:len-i < n-1 ;選擇最小的數後面的全部數,然後從最小的數前面選擇n-1-len+i個數;
當然,這樣做有個問題:因為是每次選擇一個數,我們該如何記錄選擇的數的原順序?
其實這個問題可以很好地用樹的思想解決:
我們可以利用遍歷樹的方式,先計算最小的數之前的部分,然後輸出最小的數,在計算最小的數之後的部分,使用遞迴實現,很簡單的。
函式的簡單結構如下:
delete()
{
delete(font); 計算最小的數之前的部分
put(min); 輸出最小的數
delete(last); 計算最小的數之後的部分
}
//上面只是簡單的邏輯,用C語言實現的話還得費些功夫,沒什麼難度,但是比較麻煩,最麻煩的是陣列下標的控制,大家可以結合我的程式碼分析分析。
特殊情況:當你只需要刪除0個數時,將原陣列整個輸出一遍就行了,不必繼續往下遞迴了,這樣可以節約很多時間。
下面放出我的程式碼:

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

static int delete(int *, int, int);

static int low(int, int);

int main()
{
    int a[] = {1,3,2,4,7,0,5};
    // int a[] = {1,2,6,3,4};
    int n = sizeof(a) / sizeof(a[0]);
    delete(a,n,n-4);
    return 0;
}

int delete(a,n,d)
int * a;
int n, d;
{
    if
(d <= 0) return 0; if (n == d) { for (int i = 0; i < n; i++) printf("%4d",a[i]); return n; } int min = 0; for (int i = 1; i < n; i++) { if (a[i] < a[min]) min = i; } delete(a,min,d-n+min); printf("%4d"
,a[min]); delete(&a[min+1],n-min-1,low(n-min,d)-1); return n; } int low(int x, int y) { return x<y?x:y; }

貪心很簡單,不如動規那樣繁瑣,所以到這裡貪心演算法基本上可以結了,希望大家多敲程式碼,多磨練自己。最近在給一個大一的學弟上C語言基礎課,改天我會總結一下比較有意思的知識點,跟大家分享一下。
我是演算法吹,以後會給大家帶來更多精彩的演算法。這裡寫圖片描述