數字刪除問題是典型的貪心算法問題,也是最簡單的貪心算法,通過學習數字刪除問題可以了解並理解貪心算法,可在以后的算法設計中靈活運用思路。
本文對數字刪除問題給出了兩種解法用來做比較,一種用覆蓋刪除的算法,一種貪心算法。所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列局部最優的選擇,即貪心選擇來達到。它所做的每一個選擇都是當前狀態下具有某種意義的最好選擇,即貪心選擇;並且每次貪心選擇都能將問題化簡為一個更小的與原問題具有相同形式的子問題。文中首先描述問題,然后對其分析,證明其具有最優子結構性質和貪心選擇性質,緊接着對分析次算法的復雜度。
1、數字刪除問題的描述
給定n位正整數m,去掉其中任意1≤k<n個數字后,剩下的數字按原次序排列組成一個新的正整數。且這個正整數是去掉k位數字之后最小的。
對於給定的n 位正整數m和正整數k,設計一個算法找出剩下數字組成的新數最小的刪數方案。
例如正整數m為2658941,去掉其中n為5個數字后,剩下的數字按原次序組成新數最小的為數值21。
當去掉的數字位數大於正整數位數時,將會給出超位提醒。
2、算法分析
2.1 不具備貪心算法的覆蓋刪除算法分析
對於n位正整數m可以表示為
, 去掉其中任意k位數,其中1≤k<n,則余下的數字按原次序排列組成一個新的正整數,且這個正整數最小。假設數字在去掉刪除數后的最優解為
,即此數為按原次序排列組成一個新的最小正整數。
算法中采用了一種覆蓋刪除的方法,即如果
,則不用采取覆蓋,保持原次序,若
,即后一位比前一位大時,則
,利用覆蓋刪除的方法將前一位大數刪除,並由后一位的小數代替。將此邏輯依次從
比較到
,則得出的正整數位數仍為n,即為最小正整數
。
對於
而言,刪除一位數字后,原問題
變成了對n位數字刪除k-1個數的新問題。新問題和原問題相同,問題規模n位正整數沒有變化,而刪除都掉的個數由k減少為k-1。對於剩下的數字,將繼續利用覆蓋刪除的方法進行下去。而且每一次覆蓋刪除過后便會從頭開始,重新進行比較,然后覆蓋。若n-k=2,則基本這時m已經變成了
(以通過比較發現
最小時)仍然為n位,通過輸出指針只讀取兩次,則輸出的為
是最小正整數。
2.2 貪心算法算法分析
對於n位正整數m可以表示為
, 去掉其中任意k位數,其中1≤k<n,則余下的數字按原次序排列組成一個新的正整數,且這個正整數最小。假設數字在去掉刪除數后的最優解為
,即此數為按原次序排列組成一個新的最小正整數。
算法中采用貪心算法方法,即如果
,則不采取措施,保持原次序,若
,即后一位比前一位大時,則刪除
(對於其他的數字也是相同的,此處只是舉了一個具體的例子,便於大家理解,其具有代表性)。得到的數字就是n-1位中最小的正整數,即為
。
對於
而言,刪除一位數字后,原問題
變成了從
對n-1位數字刪除k-1個數的新問題。新問題和原問題相同,問題規模n減小為n-1,刪除的數字個數由k減少為k-1。對於剩下的數字,將繼續利用此方法進行下去,直至刪去k個數為止。刪除k個數字過后剩下的便是n-k位中最小的數值了。
2.3貪心選擇性質證明
根據m數的位數及數值的特性,對其分解則:m=
。
進行第一次數字刪除時:m(1)=
假設刪除的不是時:m(2)=
因為,且,所以m(1)<m(2)
因此數字刪除問題滿足貪心選擇性質。
3、程序實現與分析
3.1基於C語言的覆蓋刪除數字程序實現:
1 fp=fopen("input.txt","r");//讀取文檔內容 2 if(fp==NULL){ 3 printf("打不開在此文件!\n"); 4 exit(0); 5 } 6 fscanf(fp,"%s%d\n",a,&n); 7 if(n>=strlen(a)) //如果要刪除的位數大於等於輸入的數字位數,將給出提示! 8 { 9 printf("刪除位數過大!\n"); 10 return; 11 } 12 while(n>0) 13 { 14 i=0; //每次開始將i初始化為0,表示重新開始檢測下降點 15 while(i<strlen(a) && a[i]<=a[i+1]) //算法最為關鍵的部分 ,檢測從第幾位開始進行刪除覆蓋 16 i++; 17 for(j=i;j<strlen(a);j++) //覆蓋實現刪除效果 18 a[j]=a[j+1]; 19 n--; 20 } 21
input.txt:
2658941
5
output.txt:
21
從第一位數開始一直比較到最后一位,若前一位比后一位大則后一位將前一位覆蓋。
3.2滿足貪心選擇性質的貪心算法程序實現:
1 while(k>x&&m==0) 2 {i=i+1; 3 if(a[i-1]>a[i]) //出現遞減,刪除遞減的首數字 4 {printf("%d",a[i-1]); 5 for(j=i-1;j<=n-x-2;j++) 6 a[j]=a[j+1]; 7 x=x+1; //x統計刪除的個數 8 i=0; //從頭開始查遞減區間 9 } 10 if(i==n-x-1) //已無遞減區間,m=1脫離循環 11 m=1; 12 } 13 printf("\n刪除后所得最小數:");
若出現遞減,則直接刪除遞減的首數字。
4、兩種算法對比
覆蓋刪除算法雖然程序設計與實現比較簡單但是對於計算機來說計算量比較大,而且此程序運行時會一一做比較,比較完了之后若有滿足條件的便會覆蓋掉,當覆蓋過后程序不會接着往下運行,它會重新開始再次進行比較,看是否滿足條件的,計算量比較大,若數字比較龐大的話,會比較浪費時間,算法時間復雜度為O(n2),空間復雜度為O(n2)。而對於貪心算法而言,就相對簡單了,數字刪除問題貪心算法思路是每一步總是選擇一個使剩下的數最小的數字刪除,即按高位到低位的順序搜索,若各位數字遞增,則刪除最后一個數字;否則刪除第一個遞減區間的首字符,這樣刪一位便形成了一個新的數字串。按上述規則再刪除下一個數字,與覆蓋刪除不同的是,它不會回頭,會一直比較下去,具有貪心選擇性質和最有子結構性質,而且它的算法時間復雜度為O(n),空間復雜度為O(n),比覆蓋刪除小很多,在算法運行上面也會節約很多時間。
