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

2021-06-09 00:54:24 字數 2747 閱讀 9857

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

給出公升序排列的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指定任意的一組公升序面值。

#include "stdio.h"

#include "conio.h"

static int values=;/*公升序排列的所有面值*/

void main()

else

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

getchar();

}int recursion(int j, int sum)

}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證明:取a的所有不大於q的面值集合b=,由命題1得,b也可以為q找零。

設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 分析你的 的時間複...

騰訊的乙個筆試題

觀察下面一段 class classa virtual void functiona class classb class classc public classa,public classb classcaobject classa pa aobject classb pb aobject cla...

C 類 NULL物件的乙個筆試題

q 如下程式輸出什麼?class a 如果fun函式是虛函式呢?一下純屬個人解答,不知更好的解答如何 一句話回答 類的所有物件共享乙份成員函式,成員變數是物件自己擁有的。要分清楚類和物件之間的區別。編譯器編譯時會儲存類的定義,包括函式啊之類的。p指向的是沒有分配空間的,類a的指標 p呼叫fun的時候...