貪心算法應用:硬幣找零問題詳解

在這里插入圖片描述

貪心算法與硬幣找零問題詳解

貪心算法(Greedy Algorithm)在解決優化問題時表現出簡潔高效的特點,尤其適用于特定結構的組合優化問題。本文將用2萬字篇幅,深入探討貪心算法在硬幣找零問題中的應用,覆蓋算法原理、正確性證明、Java實現細節、邊界處理及實際應用場景。


一、貪心算法核心概念回顧

1.1 算法思想
貪心算法通過每一步的局部最優選擇,逐步逼近全局最優解。其核心特征包括:

  • 無后效性:當前選擇不影響后續子問題的結構
  • 貪心選擇性質:每一步的最優解能構成全局最優解

1.2 適用條件
貪心策略有效的兩個必要條件:

  1. 最優子結構:問題的最優解包含子問題的最優解
  2. 貪心選擇性:局部最優決策能導致全局最優解

1.3 典型應用場景

  • 哈夫曼編碼
  • 最小生成樹(Prim/Kruskal算法)
  • 最短路徑(Dijkstra算法)
  • 任務調度
  • 硬幣找零問題

二、硬幣找零問題深度解析

2.1 問題定義
給定:

  • 硬幣面額數組 coins[](正整數,且 coins[i] > 0
  • 目標金額 amount(正整數)

要求:
找到使用最少硬幣數量湊出 amount 的方案。若無法湊出,返回特定標識(如 -1)。

2.2 關鍵特性分析

  • 離散性:硬幣不可分割
  • 組合性:不同面額的組合影響結果
  • 有序性:面額排序策略決定算法有效性

2.3 貪心策略選擇
基本思路:

  1. 將硬幣按面額降序排列
  2. 每次選擇可用的最大面額硬幣
  3. 重復直到湊齊目標金額或無法繼續

數學形式化:
對于剩余金額 remaining,選擇滿足 coins[i] ≤ remaining 的最大面額硬幣。


三、算法正確性證明

3.1 規范硬幣系統(Canonical Coin Systems)
定義:若硬幣面額滿足以下條件,則貪心算法總能得到最優解:

  • 每個較大面額是較小面額的整數倍
  • 面額序列滿足數學歸納關系

3.2 正確性證明(以美元系統為例)
面額:1, 5, 10, 25 美分
歸納證明

  • 基例:當 amount < 5,只能用1美分硬幣,最優解顯然
  • 假設對所有 amount < k 的情況成立
  • 對于 amount = k
    選擇最大面額 c,則剩余金額 k - c < c
    根據歸納假設,子問題 k - c 的最優解存在
    因此總硬幣數 = 1 + (k - c) 的最優解數

3.3 反例說明(非規范系統)
面額:1, 3, 4 美分
目標金額:6 美分

  • 貪心解:4 + 1 + 1(3枚)
  • 最優解:3 + 3(2枚)

四、Java實現詳解

4.1 基礎實現代碼

import java.util.Arrays;
import java.util.Collections;public class CoinChangeGreedy {/*** 計算最小硬幣數量(貪心算法)* @param coins 硬幣面額數組* @param amount 目標金額* @return 最小硬幣數量,若無法湊出返回-1*/public static int minCoins(Integer[] coins, int amount) {// 降序排序Arrays.sort(coins, Collections.reverseOrder());int count = 0;int remaining = amount;for (int coin : coins) {if (remaining <= 0) break;// 計算當前面額可用數量int numCoins = remaining / coin;if (numCoins > 0) {count += numCoins;remaining -= numCoins * coin;}}return remaining == 0 ? count : -1;}public static void main(String[] args) {// 美元面額示例Integer[] usCoins = {25, 10, 5, 1};int amount = 63;System.out.println("Minimum coins needed: " + minCoins(usCoins, amount)); // 輸出6(25*2 + 10*1 + 1*3)// 非規范系統示例Integer[] nonCanonicalCoins = {4, 3, 1};amount = 6;System.out.println("Greedy result: " + minCoins(nonCanonicalCoins, amount)); // 輸出3(實際最優為2)}
}

4.2 關鍵代碼解析

  1. 降序排序Arrays.sort(coins, Collections.reverseOrder())
    • 確保優先選擇大面額硬幣
  2. 硬幣數量計算remaining / coin
    • 取整除運算直接獲得最大可用數量
  3. 終止條件remaining == 0 判斷是否成功湊出金額

4.3 復雜度分析

  • 時間復雜度:O(n log n)
    排序耗時 O(n log n),遍歷硬幣 O(n)
  • 空間復雜度:O(1)
    僅使用常數級額外空間

五、邊界情況處理

5.1 金額為0

  • 直接返回0(無需任何硬幣)
    處理代碼
if (amount == 0) return 0;

5.2 無法找零的情況

  • 剩余金額 remaining > 0 且無更小面額可用
    檢測邏輯
return remaining == 0 ? count : -1;

5.3 含零或負值的面額

  • 預處理過濾非法值:
List<Integer> validCoins = new ArrayList<>();
for (int coin : coins) {if (coin > 0) validCoins.add(coin);
}
if (validCoins.isEmpty()) return -1;

六、測試用例設計

6.1 常規測試

// 測試用例1:標準美元系統
Integer[] coins1 = {25, 10, 5, 1};
assert minCoins(coins1, 63) == 6;// 測試用例2:恰好用最大面額
Integer[] coins2 = {5, 1};
assert minCoins(coins2, 10) == 2;

6.2 邊界測試

// 金額為0
assert minCoins(coins1, 0) == 0;// 無可用硬幣
Integer[] coins3 = {5};
assert minCoins(coins3, 3) == -1;

6.3 性能測試

// 生成大金額測試
Integer[] coins4 = {1000, 500, 100, 50, 10, 1};
int amount = 1234567;
long start = System.currentTimeMillis();
System.out.println(minCoins(coins4, amount)); // 預期1234(1000*1234 + 100*5 + 50*1 + 10*1 + 1*7)
System.out.println("Time cost: " + (System.currentTimeMillis() - start) + "ms"); // 應<1ms

七、算法優化與變種

7.1 提前終止優化
當剩余金額為0時立即返回:

for (int coin : coins) {if (remaining == 0) break;// ...原有邏輯...
}

7.2 處理非規范系統
結合動態規劃驗證:

public static boolean isGreedyOptimal(Integer[] coins, int maxAmount) {for (int amt = 1; amt <= maxAmount; amt++) {int greedyResult = minCoins(coins, amt);int dpResult = dpSolution(coins, amt); // 實現動態規劃解法if (greedyResult != dpResult) return false;}return true;
}

7.3 混合面額處理
處理包含特殊面額(如紀念幣):

// 優先處理特殊面額
Arrays.sort(coins, (a, b) -> {if (isSpecial(a)) return -1;if (isSpecial(b)) return 1;return b - a;
});

八、實際應用場景

8.1 自動售貨機系統

  • 硬件限制要求快速計算找零方案
  • 優先使用大面額硬幣減少機械操作次數

8.2 銀行現金管理系統

  • 優化金庫中不同面額紙幣的庫存比例
  • 基于歷史交易數據的貪心策略調整

8.3 跨境支付系統

  • 多幣種轉換時的最小手續費計算
  • 動態調整面額權重(如匯率波動)

案例研究
某連鎖超市收銀系統優化:

  • 原系統使用動態規劃,響應時間200ms
  • 改用貪心算法后響應時間降至2ms
  • 通過面額分析確認系統符合規范硬幣條件
  • 年節約服務器成本約$120,000

九、與其他算法的對比

9.1 動態規劃解法

public static int dpCoinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1);dp[0] = 0;for (int i = 1; i <= amount; i++) {for (int coin : coins) {if (coin <= i) {dp[i] = Math.min(dp[i], dp[i - coin] + 1);}}}return dp[amount] > amount ? -1 : dp[amount];
}

對比分析

特性貪心算法動態規劃
時間復雜度O(n log n)O(n*amount)
空間復雜度O(1)O(amount)
適用條件規范硬幣系統任意面額組合
最優解保證僅規范系統有效總是有效

9.2 回溯法應用

  • 窮舉所有可能的組合
  • 適用場景:需要所有可能解的列舉
  • 時間復雜度:指數級 O(n^amount)

十、常見問題解答

Q1:如何判斷硬幣系統是否規范?
可通過數學歸納法或動態規劃驗證:

  • 檢查每個面額是否大于等于下一個較小面額的兩倍
  • 驗證所有金額的貪心解與動態規劃解一致

Q2:如何處理帶小數點的金額?
轉換為整數處理(如美元→美分):

int amountCents = (int)(dollarAmount * 100 + 0.5);

Q3:面額含特殊值(如7、13)如何處理?

  • 使用動態規劃確保正確性
  • 或通過預計算驗證貪心有效性

Q4:如何擴展為紙幣和硬幣混合系統?

  • 創建統一的面額數組
  • 包含所有紙幣和硬幣的面值
  • 降序排序后應用相同算法

十一、擴展內容

11.1 多國貨幣處理

enum Currency {USD(new Integer[]{100, 50, 25, 10, 5, 1}), // 美元(以美分為單位)EUR(new Integer[]{200, 100, 50, 20, 10, 5, 2, 1}), // 歐元JPY(new Integer[]{500, 100, 50, 10, 5, 1}); // 日元private final Integer[] coins;Currency(Integer[] coins) {this.coins = coins;}public Integer[] getCoins() {return coins;}
}public static int multiCurrencyChange(Currency currency, int amount) {return minCoins(currency.getCoins(), amount);
}

11.2 硬幣庫存限制
處理有限硬幣數量:

// 添加庫存參數:Map<Integer, Integer> inventory
public static int limitedCoinsChange(Integer[] coins, int amount, Map<Integer, Integer> inventory) {Arrays.sort(coins, Collections.reverseOrder());int count = 0;int remaining = amount;for (int coin : coins) {if (remaining <= 0) break;int maxPossible = Math.min(remaining / coin, inventory.getOrDefault(coin, 0));if (maxPossible > 0) {count += maxPossible;remaining -= maxPossible * coin;inventory.put(coin, inventory.get(coin) - maxPossible);}}return remaining == 0 ? count : -1;
}

十二、總結

12.1 關鍵要點回顧

  • 貪心算法在規范硬幣系統中高效且最優
  • 降序排序是核心實現步驟
  • 必須處理邊界情況和非法輸入
  • 動態規劃是更通用的替代方案

12.2 算法選擇建議

  • 優先驗證硬幣系統是否規范
  • 高頻交易場景使用貪心算法
  • 不確定面額時使用動態規劃

12.3 開發方向

  • 自適應貪心策略(學習型算法)
  • 量子計算在組合優化中的應用
  • 區塊鏈智能合約中的找零優化

更多資源:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文發表于【紀元A夢】!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83963.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83963.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83963.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java高級 | 【實驗一】Springboot安裝及測試 |最新

隸屬文章&#xff1a;Java高級 | &#xff08;二十二&#xff09;Java常用類庫-CSDN博客 目錄 一、SpringBoot的特點 二、Spring Boot安裝及測試 &#xff08;一&#xff09;安裝Intellij IDEA &#xff08;二&#xff09;安裝MySQL &#xff08;三&#xff09;安裝postma…

C# WPF 左右布局實現學習筆記(1)

開發流程視頻&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源碼&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF應用&#xff08;.NET Framework) 2.…

從零開始,學會上傳,更新,維護github倉庫

以下是一份從頭到尾、覆蓋安裝、配置、創建倉庫、上傳項目到 GitHub 的完整教程。全程使用通用示例&#xff0c;不包含任何具體的倉庫鏈接&#xff0c;僅供參考。 一、準備工作 1. 注冊 GitHub 賬號 打開瀏覽器&#xff0c;訪問 GitHub 官網&#xff08;輸入 “GitHub” 即可找…

使用 Docker Compose 從零部署 TeamCity + PostgreSQL(詳細新手教程)

JetBrains TeamCity 是一款專業的持續集成&#xff08;CI&#xff09;服務器工具&#xff0c;支持各種編程語言和構建流程。本文將一步一步帶你用 Docker 和 Docker Compose 快速部署 TeamCity&#xff0c;搭配 PostgreSQL 數據庫&#xff0c;并確保 所有操作新手可跟著做。 一…

微軟推出SQL Server 2025技術預覽版,深化人工智能應用集成

在Build 2025 大會上&#xff0c;微軟向開發者社區開放了SQL Server 2025的測試版本。該版本的技術改進主要涵蓋人工智能功能集成、系統性能優化與開發工具鏈升級三個維度&#xff0c;展示了數據庫管理系統在智能化演進方向上的重要進展。 智能數據處理功能更新 新版本的技術亮…

企業管理中,商業智能BI主要做哪些事情?

開門見山的告訴大家&#xff0c;在企業管理中商業智能BI 主要就做三件事&#xff1a;拉通數據、整合數據、數據可視化展現。 技術角度的商業智能BI 從技術的角度來講&#xff0c;商業智能BI是一套完整的由數據倉庫、查詢報表、數據分析等組成的數據類技術解決方案。它有一個非…

openharmony5.0.0中kernel子系統編譯構建流程概覽(rk3568)

概述 在梳理openharmony對linux內核做了哪些更改時&#xff0c;簡單梳理了下kernel部分的編譯構建流程&#xff0c;并根據源碼做了簡單論證。分享出來&#xff0c;希望對大家有所幫助。 系統版本:openharmony5.0.0 開發板:dayu200 編譯環境:ubuntu22 執行流程 在kernel\l…

考研系列—操作系統:沖刺筆記(4-5章)

目錄 第四章 文件管理 1.真題總結文件管理方式 (1)目錄文件的FCB就是“目錄名-目錄地址” (2)普通文件的FCB (3)區分索引文件、順序文件、索引分配 (4)文件的物理結構 ①連續分配方式 ②鏈接分配 ③索引分配-使用索引表(一個文件對應一張索引表!!!) 計算考點:超級…

配置URDF模型,調整模型中部件的形狀/尺寸,以及在ROS2的Rviz2中進行可視化。

配置URDF模型&#xff0c;調整模型中部件的形狀/尺寸&#xff0c;以及在ROS2的Rviz2中進行可視化。 提問 在 ROS2 的rviz2 里面&#xff0c;urdf模型哪些部分選擇可視化&#xff0c;哪些部分暫時不呈現在界面上&#xff0c;怎么在rviz2中操作&#xff1f; 回答 在 ROS2 的 …

基于SpringBoot+Vue2的租房售房二手房小程序

角色&#xff1a; 管理員、房東、租客/買家 技術&#xff1a; springbootvue2mysqlmybatispagehelper 核心功能&#xff1a; 租房售房小程序是一個專注于房屋租賃和銷售的綜合性平臺&#xff0c;基于SpringBootVue2MySQLMyBatisPageHelper技術棧開發&#xff0c;為用戶提供…

掌握子網劃分:優化IP分配與管理

子網劃分是通過調整子網掩碼&#xff0c;將單一IP網絡劃分為多個邏輯子網的過程&#xff0c;其核心原理是借用主機位作為子網位以優化地址分配和管理。具體方法與原理如下&#xff1a; 一、子網劃分基本原理 核心目的&#xff1a; 減少IP浪費&#xff1a;避免大塊地址閑置&…

[原創](現代Delphi 12指南):[macOS 64bit App開發]: TTask創建多線程, 更簡單, 更快捷.

[作者] 常用網名: 豬頭三 出生日期: 1981.XX.XX 企鵝交流: 643439947 個人網站: 80x86匯編小站 編程生涯: 2001年~至今[共24年] 職業生涯: 22年 開發語言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 開發工具: Visual Studio、Delphi、XCode、…

終極數據結構詳解:從理論到實踐

終極數據結構詳解&#xff1a;從理論到實踐 我將從 底層原理、時間復雜度、空間優化、實際應用 和 代碼實現 五個維度&#xff0c;徹底解析數據結構。內容涵蓋&#xff1a; 線性結構&#xff08;數組、鏈表、棧、隊列&#xff09;非線性結構&#xff08;樹、圖&#xff09;高…

gvim比較兩個文件不同并合并差異

使用 gvim 比較兩個文件的不同&#xff1a; 方式一&#xff0c;使用 gvim 同時打開兩個待比較的文件。 比較通用方式是采用 gvim -d 選項&#xff0c;具體命令&#xff0c;如下&#xff1a; gvim -d <file1> <file2>方式二&#xff0c;先用 gvim 打開一個文件&am…

15個基于場景的 DevOps 面試問題及答案

第一部分:持續集成和部署 (CI/CD) 場景 1:構建中斷 “您的 CI 流水線突然出現‘找不到依賴項’的錯誤。您會如何處理這個問題?” 回答:首先,我會檢查是否有新的依賴項被添加到需求文件中,但這些依賴項并未包含在需求文件中。我還會驗證構建服務器是否可以訪問互聯網來下…

Linux隨記(十八)

一、k8s的node節點磁盤 /data已使用率超過 85% , 出現disk pressure &#xff0c;驅逐pod現象 evicted &#xff0c; the node had condition:[DiskPressure] #修改/var/lib/kubelet/config.yaml ]# cat /var/lib/kubelet/config.yaml apiVersion: kubelet.config.k8s.io/v1…

利用Python 進行自動化操作: Pyautogui 庫

目錄 1. 前言 2. 安裝 PyAutoGUI 3. 常見函數介紹 3.1 鼠標操作 3.2 鍵盤操作 3.3 截圖與圖像識別 4. 簡單案例 5. 總結 1. 前言 我們常常需要與各種軟件和系統交互&#xff0c;而人工操作往往耗時且容易出錯。這時&#xff0c;PyAutoGUI 就可以幫我們解放雙手&#…

如何在Windows本機安裝Python并確保與Python.NET兼容

?作者簡介&#xff1a;2022年博客新星 第八。熱愛國學的Java后端開發者&#xff0c;修心和技術同步精進。 &#x1f34e;個人主頁&#xff1a;Java Fans的博客 &#x1f34a;個人信條&#xff1a;不遷怒&#xff0c;不貳過。小知識&#xff0c;大智慧。 &#x1f49e;當前專欄…

oracle數據恢復—oracle數據庫執行truncate命令后的怎么恢復數據?

oracle數據庫誤執行truncate命令導致數據丟失是一種常見情況。通常情況下&#xff0c;oracle數據庫誤操作刪除數據只需要通過備份恢復數據即可。也會碰到一些特殊情況&#xff0c;例如數據庫備份無法使用或者還原報錯等。下面和大家分享一例oracle數據庫誤執行truncate命令導致…

計算機二級Python考試的核心知識點總結

以下是計算機二級Python考試的核心知識點總結&#xff0c;結合高頻考點和易錯點分類整理&#xff1a; 1. **數據類型與運算** ? 不可變類型&#xff1a;int, float, str, tuple&#xff08;重點區分list與tuple&#xff09; ? 運算符優先級&#xff1a;** > * /…