国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

面試算法:在整形數組中構建元素之和能整除數組長度的子集

2019-11-08 19:33:56
字體:
來源:轉載
供稿:網友

更詳細的講解和代碼調試演示過程,請參看視頻 如何進入google,算法面試技能全面提升指南

假設A是一個整數數組,長度為n,數組中的元素可能是重復的。設計一個算法,找到一系列下標的集合I = {i(0), i(1), i(2)….i(n)}. 使得(A[i(0)] + A[i(1)] + … A[i(n)] ) mod n = 0.例如假定A = {711, 704, 427, 995, 334, 62, 763, 98, 733, 721}, 于是I = {0,1,3}, 因為(A[0] + A[1] + A[3] ) mod 10 = 0. 請給出一個有效的算法找到滿足條件的集合I, 無論A的元素如何取值,這樣的集合總是存在的。

這是一道較為復雜的算法題,能在一個小時內完成絕非易事。我們需要解決兩個問題,第一需要證明,為何這樣的集合肯定存在,第二,集合存在,如何把它給挖掘出來。我們先證明第一個問題。

1:如果數組A中含有元素它的值是0,那么滿足條件的集合存在,這個集合就只包含元素0.

2:如果數組A只有一個元素,也就是A的長度只有1,那么A本身就是滿足條件的集合。

3:如果A包含不只一個元素,我們用歸納法來證明。假設n=k時,我們能從A中找到給定集合,使得(A[i(0)] + A[i(1)] + … A[i(n)] ) mod n = 0,那么當n=k+1時,我們從數組A中任意取出一個元素,如果被拿走的這個元素值是1,那么根據歸納法,我們可以從剩下的k個元素中,找到一個子集,子集中的元素之和能夠整除k, 把子集中的元素加上拿走的那個值為1的元素形成新的集合,這個集合之和能夠整除k+1.

如果拿走的元素值為t > 1, 剩下的元素個數為k, 那么肯定有 k > k+ 1 - t。我們從剩下的k 個元素中,隨便選出 k+1-t 個元素,在這些元素中,根據歸納法,肯定存在一個子集,使得子集元素的和能整除 k + 1 - t. 把這些子集的元素加上前面拿走的元素,那么所形成的新集合,一定能整除 k + 1

綜上,我們就證明了,這樣的集合是一定存在的,接下來我們需要考慮的是,如何找到這個集合。

我們看看,把元素逐個加總后對n求余會有什么性質: sum = (A[0] + A[1] + …. + A[j]) mod n j 由0一直增加到n-1.

在這個過程中,一定會出現下面這種情況: 存在一個 i, 0 <= i < j, 使得 (A[0]+A[1]+…+A[i]) mod n = (A[0]+A[1] + …A[j]) mod n. (*)

當上面情況出現時,我們有(A[i+1] + A[i+2] +… + A[j]) mod n = 0;

于是(A[i+1], … ,A[j]) 就是滿足條件的子集。為何(*)所描述的情況一定會發生呢?我們知道,對某個數求余,所得結果必然小于該數,因此對n求余,那么結果一定落入到1和n-1之間。

sum = (A[0] + A[1] + …. + A[j]) mod n

j 由0一直增加到n-1, 也就是上面的計算最多會進行n 次,得到n個求余的結果,然而求余的結果最多只可能有n-1中不同情況,那么n個結果中,肯定得有出現重復的時候,一旦出現重復的時候,(*)所描述的情況就出現了。

根據上面算法原理,我們可以實現如下代碼:

public ArrayList<Integer> moduleSubSet(int[] A) { int[] B = new int[A.length]; for (int i = 0; i < B.length; i++) { B[i] = 0; } int sum = 0; ArrayList<Integer> subSet = new ArrayList<Integer>(); for (int i = 0; i < A.length; i++) { sum += A[i]; subSet.add(i); int t = sum % A.length; if (t == 0) { return subSet; } int PRe_sum = 0; if (t != 0) { if (B[t] != 0) { for (int j = 0; j < i; j++) { pre_sum += A[j]; if (pre_sum % A.length != t) { subSet.remove((Integer)j); } else { subSet.remove((Integer)j); return subSet; } } } B[t] = 1; } } return null; }

在for循環中,我們把數組A的元素逐個相加,然后對長度n求余,所得結果記為t,然后拿這個結果到另一個校驗數組B中檢驗一下,如果B[t] 的值是1,這表明(*)所描述的情況出現了,此時我們再遍歷以便(A[0]….A[j]) 把i找出來,找到i的辦法就是再次將元素逐個相加,當所得結果對n求余后,與前面算得的t相等,那么此時的元素下標i滿足條件,找到i之后,再把下標0到i從集合中去除,那么集合中剩下的下標就是對應自己中的元素在原數組中的下標。

我們再看看主入口函數的實現:

public static void main(String[] args) { ArrayAndString as = new ArrayAndString(); int[] A = new int[]{1,1,1,3}; //int[] A = new int[]{711, 704, 427, 995, 334, 62, 763, 98, 733, 721}; ArrayList<Integer> subSet = as.moduleSubSet(A); System.out.println("sub set is: "); for (int i = 0; i < subSet.size(); i++) { System.out.print(subSet.get(i) + " "); } }

上面代碼運行后結果為: sub set is: 1 2 3 4 也就是說(A[1] + A[2] + A[3] + A[4]) mod 10 = 0, 大家可以自己檢測一下,所得結果確實是正確的。

更多技術信息,包括操作系統,編譯器,面試算法,機器學習,人工智能,請關照我的公眾號: 這里寫圖片描述


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新宁县| 贵港市| 江西省| 永宁县| 卓尼县| 定安县| 白水县| 虎林市| 仙游县| 宝鸡市| 大厂| 金坛市| 扎鲁特旗| 开封市| 内丘县| 汶川县| 邳州市| 华蓥市| 久治县| 穆棱市| 驻马店市| 绥德县| 定远县| 开平市| 扬中市| 建水县| 定边县| 墨江| 毕节市| 金川县| 赣州市| 体育| 永善县| 广东省| 衡水市| 祁阳县| 大新县| 正宁县| 桓仁| 定结县| 宝兴县|