1. 程式人生 > >劍指offer面試題14:剪繩子(Java 實現)

劍指offer面試題14:剪繩子(Java 實現)

題目:給你一根長度位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));
	}
}