leetcode 322

7 個月前

這道題相似於徹底揹包問題,每一個物品均可以無限使用,可是要求揹包必須裝滿,並且要求揹包中的物品數目最少, 概括爲數學問題就是,數組

  • v[i]:表明每種硬幣的價值
  • x[i]:表明每種硬幣拿的個數,0<=x[i]<=amount/v[i]
  • 所求問題能夠概括爲:
  • 在知足:amount=v1x1+v2x2+v3x3+...+vnxn 的條件下
  • 求: target=min{x1+x2+x3+....xn}
  • 最簡單的一種思路就是把全部{xi}的組合所有拿出來,而後讓target最小便可,利用遞歸就能夠解決問題,可是時間複雜度會很高,可是若是有好的剪枝策略,也可使用
  • 另一種方法就是常規的動態規劃,利用一個amout+1長度的dp數組,記錄每個狀態的最優解,過程見程序和註釋
public int coinChange(int[] coins, int amount) {
    	if(coins.length == 0)
            return -1;
    	
    	//聲明一個amount+1長度的數組dp,表明各個價值的錢包,第0個錢包能夠容納的總價值爲0,其它所有初始化爲無窮大
    	//dp[j]表明當錢包的總價值爲j時,所須要的最少硬幣的個數
    	int[] dp = new int[amount+1];
    	Arrays.fill(dp,1,dp.length,Integer.MAX_VALUE);
    	
    	//i表明可使用的硬幣索引,i=2表明只在第0個,第1個,第2個這三個硬幣中選擇硬幣
    	for (int i = 0; i < coins.length; i++) {
    		/**  * 當外層循環執行一次之後,說明在只使用前i-1個硬幣的狀況下,各個錢包的最少硬幣個數已經獲得,  * 有些錢包的值仍是無窮大,說明在僅使用前i-1個硬幣的狀況下,不能湊出錢包的價值  * 如今開始再放入第i個硬幣,要想放如w[i],錢包的價值必須知足j>=w[i],因此在開始放入第i個硬幣時,j從w[i]開始 */
		for (int j = coins[i]; j <= amount; j++) {
			/**  * 若是錢包當前的價值j僅能容許放入一個w[i],那麼就要進行權衡,以得到更少的硬幣數  * 若是放入0個:此時錢包裏面硬幣的個數保持不變: v0=dp[j]  * 若是放入1個:此時錢包裏面硬幣的個數爲: v1=dp[j-coins[i]]+1  * 【前提是dp[j-coins[i]]必須有值,若是dp[j-coins[i]]是無窮大,說明沒法湊出j-coins[i]價值的錢包,  * 那麼把w[i]放進去之後,天然也湊不出dp[j]的錢包】  * 因此,此時當錢包價值爲j時,裏面的硬幣數目爲 dp[j]=min{v0,v1}  * 若是錢包當前價值j可以放入2個w[i],就要再進行一次權衡  * 若是不放人第2個w[i],此時錢包裏面硬幣數目爲,v1=dp[j]=min{v0,v1}  * 若是放入第2個w[i], 此時錢包裏面硬幣數目爲,v2=dp[j-coins[i]]+1  * 因此,當錢包的價值爲j時,裏面的硬幣數目爲dp[j]=min{v1,v2}=min{v0,v1,v2}  * 錢包價值j能容許放入3個,4個.........w[i],不斷更新dp[j],最後獲得在僅使用前i個硬幣的時候,每一個錢包裏的最少硬幣數目 */
			if(dp[j-coins[i]] != Integer.MAX_VALUE) {
				dp[j] = Math.min(dp[j], dp[j-coins[i]]+1);
			}
		}
	}
    	if(dp[amount] != Integer.MAX_VALUE)
    		return dp[amount];
    	return -1;
    }
相關文章
相關標籤/搜索