劍指offer面試題14:剪繩子(Java 實現)
阿新 • • 發佈:2018-12-15
題目:給你一根長度位n的繩子,請把繩子減成m段(m,n都是整數,n>1並且m>1),每段繩子的長度記為k[0],k[1],k[2],....k[m]。請問k[0] ✖️k[1]✖️k[2]....✖️k[m]可能的最大乘積是多少?例如:當繩子的長度是8時,我們把它減成長度分別為2,3,3三段,此時得到的最大乘積是18.
動態演算法(由上到下分析,由下到上編碼):
設求繩子擷取成若干段後繩子的乘積最大值是f(n),當我們擷取長度是i的繩子時 ,有多種可能1,2,3,4,5......n-1;因為對應的f(i)*f(n-i)也不同,我們f(n)求得得事最大值,因此f(n) = Max(f(i) *f(n-i));
這是一個由上而下的遞迴公式,但是有很多重複的問題,因此我們想的是從下往上進行程式碼編寫。
public class Test2 { public static void main(String[] args) { int length = 18; System.out.println(maxProductAfterCutting(length)); } private static long maxProductAfterCutting(int length) { if(length<2) return 0; if(length==2) return 1; if(length==3) return 2; int[] products = new int[length+1]; products[0] = 0; //product陣列前四個數字用來儲存i ,方便後面計算 ;例如f(4) = max[product[2] * product[2]]=4; products[1] = 1; products[2] = 2; products[3] = 3; int max = 0; for(int i=4;i<=length;i++) { max = 0; for(int j=1;j<=i/2;j++) { if(max<products[j]*products[i-j]) max = products[j]*products[i-j]; products[i] = max; } } return products[length]; } }
運用強大數學的貪婪演算法;
我們按照以下要求裁剪繩子,儘可能裁剪長度為3的繩子,當剩下繩子的長度是1是,將它和前面一節變成4(優化為2*2),長度為2時保持不變。這樣我們裁剪出來的乘積肯定是最大的。原因:因為>3所有的問題都可以由2,3來進行表示解決。 當n>=5時 3(n-3) > 2(n-2) 因為當n>5時,我們應該儘量擷取長度為3的繩子.
public class Test2 { public static void main(String[] args) { int length = 18; System.out.println(maxProductAfterCutting(length)); } private static long maxProductAfterCutting(int length) { if(length<2) return 0; if(length==2) return 1; if(length==3) return 2; int timeOf3 = length/3; int timeOf2 = 0; if(length%3==1) { timeOf3 --; timeOf2 += 2; //將4轉化為2*2 }else if(length==2) { timeOf2 ++; } return (long) (Math.pow(3, timeOf3)*Math.pow(2, timeOf2)); } }