乙個無重複面值的找零演算法的思路與實現

2021-06-10 06:34:08 字數 2857 閱讀 4677

本題的另外乙個解法請看:乙個無重複面值的找零演算法的思路與實現(二)

在論壇上看到有人問了乙個類似的演算法題:

給出公升序排列的n個數字,比如1, 2, 3, 7, 70

找出無法被這組數字組成的最小正整數。(這組數字中每個數字最多使用一次)

(1)簡單描述你的演算法和思路。

(2)用c/c++實現

(3)分析你的**的時間複雜度和空間複雜度

解題思路:

這個問題類似於乙個硬幣找零問題的公升級版。現存在一堆面值為v1, v2, v3, ...的硬幣,每種面值的硬幣只有一枚,現在需要為顧客找出總值為sum的零錢。問不能被找零的sum的最小值是多少?

方案1:

最容易理解的實現方法是使用遞迴。

我們假定v1, v2, v3, ... vn是面值由小到大排列的所有幣種。我們從sum等於1開始,遞增的迴圈進行找零。

首先找出小於等於sum且最接近sum的面值vm。然後得出sum-vm的值,並對sum-vm繼續進行找零,找出小於等於sum-vm且小於vm的最接近面值。遞迴的找下去,如果連最小面值都被遍歷到而sum仍然沒被找完,則不能被找零。

若sum不能被無重複面值的找零,則sum即所求。否則,對sum+1進行遞迴的找零。

如下是我用c語言實現的演算法,可以直接執行。可以為values指定任意的一組公升序面值。

[cpp]view plain

copy

#include "stdio.h"

#include "conio.h"

static

intvalues=;

/*公升序排列的所有面值*/

void

main()  

else

}  if(recursion(j,sum-values[j])==-1);  

}  }  

getchar();  

}  int

recursion(

intj, 

intsum)  

}  return

recursion(k,sum-values[k]);  

}  

有同學然而實際上這種情況是不存在的。因為程式是從sum等於1開始對sum進行遞增的判斷,如果sum=k時不能被找零,則所求的最小值就是k,程式將不會繼續往下進行。也就是說上段所說的情況是不存在的,因為4已經是所求的不能被找零的最小值,程式將跳出迴圈。

接下來我們來證明演算法的正確性。

在sum=1或sum=2的情況下很明顯,演算法正確。根據數學歸納法,我們只需證明對於面值集g=,在sum=1, 2, ...,k(k>=1)都可以被正確找零的情況下,演算法對sum=k+1的驗證是正確的,即可證明演算法正確。而要證明這點,我們只需證明遞迴演算法是正確的,即取不大於且最接近sum的vm的做法是正確的。

首先我們證明一些輔助命題。如果嫌長也可以先看下面正題的證明再來查閱這兩個輔助命題。

1.對於面值集g=,若g可以為1, 2, ...,vm(m<=n)找零,則由g的前m個連續面值組成的子集a=必定可以為1, 2, ...,vm找零。

證明:首先能為sum=x找零的面值均小於等於x。(比如為5找零,零錢中肯定不會有6)。所以能為x找零的面值中可以不包含比x更大的面值。

若g能為x找零,則g中所有不大於x的面值的集合也能為x找零,因為大於x的面值在找零的時候根本不可能被用到。

已知面值集g可以為1, 2, ...vm找零,因此g的所有不大於vm的面值的集合也可以為1, 2, ...vm找零。

得證。

2.對於面值集g=,1, 2, ... ,k均可以被找零。其中q(1設q=va+vb+...(其中va, vb, ...為公升序排列且均屬於面值集合b)

1)若va=1,則將為q找零的集合中的va去掉即可表示q-1

2)若(va)-1屬於b,只需將q的找零集合中的va替換成va-1即可表示q-1.

3)若(va)-1不屬於b,由命題1可知b可以為1,2,...vt找零。由於1

綜上可得,q-1肯定可以被b找零。由於a包含b,所有q-1可以被a找零。

根據數學歸納法,可知q-2,...2,1均可以被a找零。得證。

接下來我們進入正題。

什麼情況下取不大於且最接近sum的vm的做法是正確的呢?

事實上,在1, 2, ...,sum-1都可以被找零的情況下,若sum可以被小於vm的一組面值集表示,則sum必定可以被包含vm的一組面值集表示。

可以轉化為對如下命題的證明:面值集g=,sum=1, 2, ...,k-1(k-1>=1)都可以被正確找零。g中最接近且不大於sum的面值為vm。已知sum可以被最大為vr的面值集找零,求證若v(r+1)<=sum,則sum可以被最大為v(r+1)的面值集找零。則根據數學歸納法,sum可以被最大為vm面值集合找零。

證明:

由於sum可以最大為vr的面值集合找零,令sum=vr+(sum-vr),由於最大為vr,所以(sum-vr)可以被小於vk的集合j=找零。

由命題2可知小於(sum-vr)的自然數均可以被j找零。由於(sum-v(r+1))

由於(sum-v(r+1))被j找零的面值組合中肯定不包含v(r+1),因此sum可以表示為sum=v(r+1)+(sum-v(r+1)).即(sum-v(r+1))被j找零的組合再加上v(r+1)。

因此,若sum可以被最大為vr的面值集找零,如果v(r+1)<=sum,則sum可以被最大為v(r+1)的面值集找零。

得證。

(待續)

筆試題 乙個無重複面值的找零演算法的思路與實現

在論壇上看到有人問了乙個類似的演算法題 給出公升序排列的n個數字,比如1,2,3,7,70 找出無法被這組數字組成的最小正整數。這組數字中每個數字最多使用一次 1 簡單描述你的演算法和思路。2 用c c 實現 3 分析你的 的時間複雜度和空間複雜度 解題思路 這個問題類似於乙個硬幣找零問題的公升級版...

關於Top n演算法問題的乙個思路

top n問題一直是面試熱點,舉個栗子,100000個無序數字,怎麼找出最大的前10個?如果用氣泡排序的話,就要比較100000 100000次,很顯然不行,這是最差的情況下,那麼最好的情況也要至少遍歷一遍,也就是100000次,所以,複雜度就是越接近十萬次越好。可以這樣 取前十個數,用插入排序從大...

推薦乙個做「臺」的思路

推薦乙個做 臺 的思路 雷軍在部落格中寫了一篇關於創業是否做平台的感悟 網際網路創業不妨先放下平台夢 大概的意思是說,創業做平台競爭激烈,不容易成功,不如換一種是思路,先依託於其他人等做大了,再考慮做自己的平台。keso在5g裡分享了乙個 豆丁網 www.doodii.com 這個 其實很簡單,就是...