JavaScript實現切金條問題

問題描述:

一塊金條切成兩半,是需要花費和長度數值一樣的銅板的。比如長度爲20的金條,不管切成長度多大的兩半,都要花費20個銅 板。一羣人想整分整塊金條,怎麼分最省銅板?

例如,給定數組{10,20,30},代表一共三個人,整塊金條長度爲 10+20+30=60。金條要分成10,20,30三個部分。 如果, 先把長 度60的金條分成10和50,花費60;再把長度50的金條分成20和30, 花費50;一共花費110銅板。 但是如果, 先把長度60的金條分成30和30,花費60;再把長度30金條分成10和20,花費30;一共花費90銅板。 輸入一個數組,返回分割的最小代價。

 

思路:

這個題是哈夫曼編碼問題,想把金條切成規定的多少段,選擇一個怎樣的順序能讓代價最低。我們可以認爲每一塊金條長度是一個葉節點,怎麼決定葉節點的合併順序才能讓整體的合併代價最低。而兩個葉節點合併之後產生的和就是它的合併代價。

也就是說,這個題是求所有非葉節點的值加起來最低。這個題整體就轉化爲:給了葉節點,選擇一個什麼合併順序,能夠導致非葉節點整體的求和最小。所以解題時可以反過來,把“一整條金條該如何切割”,換爲“已知需要切割的長度,如何使之加起來的代價最小”。

 

步驟:

  1. 先把需要分割的長度值,加入小根堆;
  2. 取出小根堆裏兩個最小的值,合併後的值再加入小根堆;
  3. 一直重複第二步,直到堆裏沒有值,可得到最小的和。
function lessMoney(arr){
	if (!arr || arr.length < 1) {
		return;
	};
	let res = 0;
	while(arr.length > 1){
		let cur = pollHeap(arr) + pollHeap(arr);
		res += cur;
		addHeap(arr,cur,arr.length-1);
	}
	return res;
}
function minHeap(arr){  // 建立小根堆
	for(let i = 0; i < arr.length; i++){
		while(arr[i] < arr[parseInt((i - 1)/2)]){
			swap(arr,i,parseInt((i - 1)/2));  // 交換位置
			i = parseInt((i - 1)/2);
		}
	}
	
};
function pollHeap(arr){  // 取出一個值
	minHeap(arr);
	return arr.shift();
};
function addHeap(arr,cur){  // 加入一個值
	arr.push(cur);
	let i = arr.length-1;
	while(arr[i] < arr[parseInt((i - 1)/2)]){
		swap(arr,i,parseInt((i - 1)/2))
		i = parseInt((i - 1)/2);
	}
}
function swap(arr,i,j){  // 交換位置
	let temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
console.log(lessMoney([20,30,10,50]));  // 200
// 10+20=30 30+30=60 60+50=110;  30+60+110=200

個人理解,直接使用排序數組也能解決。如果還有更好的解法,歡迎指教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章