程式設計師面試100題之十五 陣列分割

2021-08-31 23:17:08 字數 1733 閱讀 4431

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!

一、題目概述:有乙個沒有排序,元素個數為2n的正整數陣列。要求把它分割為元素個數為n的兩個陣列,並使兩個子陣列的和最接近。

假設陣列a[1..2n]所有元素的和是sum。模仿動態規劃解0-1揹包問題的策略,令s(k, i)表示前k個元素中任意i個元素的和的集合。顯然:

s(k, 1) =

s(k, k) =

s(k, i) = s(k-1, i) u

按照這個遞推公式來計算,最後找出集合s(2n, n)中與sum/2最接近的那個和,這便是答案。這個演算法的時間複雜度是o(2^n).

因為這個過程中只關注和不大於sum/2的那個子陣列的和。所以集合中重複的和以及大於sum/2的和都是沒有意義的。把這些沒有意義的和剔除掉,剩下的有意義的和的個數最多就是sum/2個。所以,我們不需要記錄s(2n,n)中都有哪些和,只需要從sum/2到1遍歷一次,逐個詢問這個值是不是在s(2n,n)中出現,第乙個出現的值就是答案。我們的程式不需要按照上述遞推公式計算每個集合,只需要為每個集合設乙個標誌陣列,標記sum/2到1這個區間中的哪些值可以被計算出來。關鍵**如下:

#include

using

namespace

std;//有乙個沒有排序,元素個數為2n的正整數陣列。要求把它分割為元素個數為n的兩個陣列,並使兩個子陣列的和最接近。

int arr = ;const

int n=5;const

int sum = 87;// 模仿動態規劃解0-1揹包問題的策略

intsolve1

() dp(2n,n,sum/2+1)就是題目的解。 */

//初始化

memset(dp,0,sizeof(dp)); for(i = 1 ; i <= 2*n ; ++i)   } } //因為這為最終答案 dp[2*n][n][sum/2+1]; i=2*n , j=n , s=sum/2+1; while(i > 0)    i--; } cout

<

solve2

()  } } //要求最優解則 空間不能優化,

return dp[n][sum/2+1];}int

solve3

()  } } for(s = sum/2+1 ; s >= 0 ; --s)  //要求最優解則空間不能優化

return

0;}int

main

(void)

二、

擴充套件問題:  交換兩個陣列元素使兩個陣列和的差最小

有兩個陣列a、b,大小都為n,陣列元素的值任意整形數,無序;

要求:通過交換a、b陣列中的元素,使[陣列a元素的和]與[陣列b元素的和]之間的差最小。

其實這個問題就是上面問題的變形,將a、b兩個陣列合併為乙個陣列,然後問題就轉化為將2*n個元素陣列分割為2個長度為n的陣列,並使兩個子陣列的和最接近。

另外,特別注意:如果陣列中有負數的話,上面的揹包策略就不能使用了(因為第三重迴圈中的s是作為陣列的下標的,不能出現負數的),需要將陣列中的所有陣列都加上最小的那個負數的絕對值,將陣列中的元素全部都增加一定的範圍,全部轉化為正數,然後再使用上面的揹包策略就可以解決了。

給我老師的人工智慧教程打call!

程式設計師面試100題之十一 陣列迴圈移位

設計乙個演算法,把乙個含有n個元素的陣列迴圈右移k位,要求時間複雜度為o n 且只允許使用兩個附加變數。不合題意的解法如下 我們先試驗簡單的辦法,可以每次將陣列中的元素右移一位,迴圈k次。abcd1234 4abcd123 34abcd12 234abcd1 1234abcd。如下所示 rights...

程式設計師面試100題之十二 求陣列中最長遞增子串行

寫乙個時間複雜度盡可能低的程式,求乙個一維陣列 n個元素 中最長遞增子串行的長度。例如 在序列1,1,2,3,4,5,6,7中,其最長遞增子串行為1,2,4,6。分析與解法 根據題目要求,求一維陣列中的最長遞增子串行,也就是找乙個標號的序列b 0 b 1 b m 0 b 0 解法一根據無後效性的定義...

程式設計師面試100題之十二 求陣列中最長遞增子串行

寫乙個時間複雜度盡可能低的程式,求乙個一維陣列 n個元素 中最長遞增子串行的長度。例如 在序列1,1,2,3,4,5,6,7中,其最長遞增子串行為1,2,4,6。分析與解法 根據題目要求,求一維陣列中的最長遞增子串行,也就是找乙個標號的序列b 0 b 1 b m 0 b 0 解法一根據無後效性的定義...