貪心算法精解(Java實現):從理論到實戰

一、貪心算法概述

貪心算法(Greedy Algorithm)是一種在每一步選擇中都采取當前狀態下最優決策的算法策略。它通過局部最優選擇來達到全局最優解,具有高效、簡潔的特點。

核心特點:

  • 局部最優選擇:每一步都做出當前看來最佳的選擇,即在當前狀態下,不考慮整體的最優解,只關注眼前的最優決策。
  • 無后效性:當前決策不會影響后續決策,也就是說,在做出當前的最優選擇后,不會改變未來狀態的決策空間和決策方式。
  • 高效性:通常時間復雜度較低,相比于一些需要窮舉所有可能性的算法,貪心算法能更快地得到結果。

適用場景:

  1. 問題具有最優子結構:即問題的最優解包含了其子問題的最優解。例如,在區間調度問題中,全局的最優區間選擇方案包含了每個子區間的最優選擇。
  2. 問題具有貪心選擇性質:通過一系列局部最優選擇可以得到全局最優解。這是貪心算法能夠應用的關鍵條件。
  3. 不需要回溯或考慮所有可能性:貪心算法在每一步都直接做出選擇,而不需要回頭修改之前的決策,也不需要考慮所有可能的情況。

二、貪心算法基本框架(Java 實現)

import java.util.List;// 假設Problem類是存儲問題相關數據的類
class Problem {private List<Item> items;public Problem(List<Item> items) {this.items = items;}public List<Item> getItems() {return items;}
}// 假設Item類是表示問題中每個元素的類
class Item {// 可以根據具體問題添加屬性和方法
}// 假設Solution類是存儲最終解決方案的類
class Solution {// 可以根據具體問題添加屬性和方法,用于存儲和操作解決方案public void add(Item item) {// 實現將item添加到解決方案中的邏輯}
}public class GreedyAlgorithm {public static Solution greedySolution(Problem problem) {// 1. 初始化解決方案Solution solution = new Solution();// 2. 對輸入進行預處理(如排序)List<Item> items = preprocess(problem.getItems());// 3. 貪心選擇過程for (Item item : items) {if (canSelect(item, solution)) {solution.add(item);}}// 4. 返回最終解return solution;}private static List<Item> preprocess(List<Item> items) {// 根據具體問題實現對輸入數據的預處理,例如排序// 這里簡單返回原數據,實際應用中需要進行處理return items;}private static boolean canSelect(Item item, Solution solution) {// 判斷當前項是否能被選中// 根據具體問題實現return true;}
}

三、經典貪心算法問題

3.1 找零錢問題(Coin Change)

import java.util.Arrays;public class CoinChange {public static int minCoins(int[] coins, int amount) {Arrays.sort(coins); // 先排序,將硬幣面額從小到大排列int count = 0;int index = coins.length - 1; // 從最大面額開始,因為要盡可能使用大面額的硬幣以減少硬幣數量while (amount > 0 && index >= 0) {if (coins[index] <= amount) {int num = amount / coins[index]; // 計算當前面額硬幣的使用數量count += num; // 將使用數量累加到總硬幣數中amount -= num * coins[index]; // 從總金額中減去已使用的硬幣金額}index--; // 嘗試下一個較小面額的硬幣}return amount == 0? count : -1; // 如果金額正好用完,返回總硬幣數;否則返回-1表示無法找零}
}

3.2 區間調度問題(Interval Scheduling)

import java.util.Arrays;public class IntervalScheduling {public static int maxNonOverlappingIntervals(int[][] intervals) {if (intervals == null || intervals.length == 0) return 0;// 按照結束時間排序,這樣能保證每次選擇的區間結束時間最早,為后續選擇留出更多空間Arrays.sort(intervals, (a, b) -> a[1] - b[1]);int count = 1; // 至少有一個區間可以選擇int end = intervals[0][1]; // 記錄當前已選區間的結束時間for (int i = 1; i < intervals.length; i++) {if (intervals[i][0] >= end) {count++; // 找到一個不重疊的區間,區間數量加1end = intervals[i][1]; // 更新當前已選區間的結束時間}}return count;}
}

四、LeetCode 經典題目解析

4.1 買賣股票的最佳時機 II(LeetCode 122)

class Solution {public int maxProfit(int[] prices) {int profit = 0;for (int i = 1; i < prices.length; i++) {if (prices[i] > prices[i - 1]) {profit += prices[i] - prices[i - 1]; // 如果今天的價格比昨天高,就進行買賣獲取利潤}}return profit;}
}

這道題的貪心策略是:只要今天的股票價格比昨天高,就進行一次買賣操作,獲取差價利潤。因為可以進行多次買賣,所以每次價格上漲都能帶來利潤,最終得到的總利潤就是最大利潤。

4.2 跳躍游戲(LeetCode 55)

class Solution {public boolean canJump(int[] nums) {int maxReach = 0;for (int i = 0; i < nums.length; i++) {if (i > maxReach) return false; // 如果當前位置超過了能到達的最大位置,說明無法到達終點maxReach = Math.max(maxReach, i + nums[i]); // 更新能到達的最大位置if (maxReach >= nums.length - 1) return true; // 如果能到達的最大位置已經超過或等于終點,說明可以到達終點}return true;}
}

這道題的貪心策略是:在遍歷數組的過程中,不斷更新能到達的最大位置。如果當前位置超過了能到達的最大位置,說明無法繼續前進;如果能到達的最大位置已經超過或等于終點,說明可以到達終點。

五、貪心算法解題技巧

  1. 排序預處理:大多數貪心問題需要先對輸入數據進行排序
    • 按開始時間、結束時間、權重等關鍵屬性排序。例如在區間調度問題中,按照區間的結束時間排序,能保證每次選擇的區間結束時間最早,為后續選擇留出更多空間。
  2. 優先隊列應用:處理需要動態獲取最優解的問題
    PriorityQueue<Integer> pq = new PriorityQueue<>();
    

優先隊列可以在每次操作中快速獲取當前的最優元素,適用于需要動態維護最優解的場景,比如在一些涉及到權重或優先級的問題中。
3.?雙指針技巧:適用于區間類問題

int left = 0, right = array.length - 1;

雙指針可以在數組或區間上進行高效的遍歷和操作,通過兩個指針的移動來解決一些與區間相關的問題,比如尋找最長不重疊區間等。
4.?貪心選擇證明

  • 交換論證法:通過交換當前貪心選擇和其他選擇,證明貪心選擇不會導致更差的結果。
  • 數學歸納法:證明對于小規模問題貪心選擇是正確的,然后假設對于規模為 n 的問題貪心選擇正確,證明對于規模為 n+1 的問題貪心選擇也正確。
  • 反證法:假設貪心選擇不是最優的,推出矛盾,從而證明貪心選擇是最優的。

六、貪心算法的局限性

  1. 不能保證全局最優:某些問題無法通過貪心算法得到最優解。因為貪心算法只考慮當前的最優選擇,而沒有考慮整體的情況,可能會陷入局部最優解。
  2. 適用范圍有限:僅適用于具有貪心選擇性質的問題。如果問題不滿足貪心選擇性質,使用貪心算法可能得到錯誤的結果。
  3. 需要嚴格證明:必須證明貪心選擇的正確性。在應用貪心算法之前,需要通過數學證明或其他方法來驗證貪心策略的有效性,否則可能無法得到正確的結果。

七、實戰建議

  1. 識別貪心性質:分析問題是否具有貪心選擇性質。可以通過嘗試一些簡單的例子,觀察是否可以通過局部最優選擇得到全局最優解。
  2. 從簡單案例入手:通過小例子驗證貪心策略。在解決復雜問題之前,先從簡單的情況開始,驗證貪心策略的正確性和有效性。
  3. 與動態規劃對比:當貪心不適用時考慮動態規劃。如果發現問題不滿足貪心選擇性質,或者貪心算法無法得到最優解,可以考慮使用動態規劃等其他算法。
  4. 邊界條件檢查:特別注意空輸入、極值等情況。在編寫代碼時,要考慮到各種可能的邊界情況,避免出現錯誤。

八、進階練習

  1. 分發餅干(LeetCode 455)
  2. 無重疊區間(LeetCode 435)
  3. 加油站問題(LeetCode 134)
  4. 任務調度器(LeetCode 621)
// 示例:分發餅干(LeetCode 455)
import java.util.Arrays;class Solution {public int findContentChildren(int[] g, int[] s) {Arrays.sort(g); // 對孩子的胃口大小進行排序Arrays.sort(s); // 對餅干的大小進行排序int i = 0, j = 0;while (i < g.length && j < s.length) {if (s[j] >= g[i]) {i++; // 如果當前餅干能滿足當前孩子的胃口,孩子數量加1}j++; // 無論是否能滿足,都嘗試下一塊餅干}return i; // 返回能滿足的孩子數量}
}

結語

貪心算法是算法設計中的重要范式,掌握它能有效解決許多實際問題。理解其核心思想并通過大量練習培養直覺是關鍵。記住,不是所有問題都適合貪心解法,當遇到困難時,不妨考慮動態規劃等其他方法。

學習建議

  1. 從簡單貪心問題入手,逐步熟悉貪心算法的應用場景和解題思路。
  2. 重點理解貪心選擇性質的證明,通過練習不同的證明方法來加深對貪心算法的理解。
  3. 對比不同解法的優劣,了解貪心算法與其他算法(如動態規劃)的區別和聯系,在實際應用中選擇最合適的算法。
  4. 參與在線編程競賽鍛煉實戰能力,通過解決各種實際問題來提高自己的算法水平和編程能力。

希望這篇 Java 實現的貪心算法指南對你的學習有所幫助!如果有任何問題,歡迎在評論區留言討論。

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

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

相關文章

深度學習框架:PyTorch使用教程 !!

文章目錄 一、PyTorch框架簡介 1.1 什么是PyTorch 1.2 PyTorch的優勢 二、從入門到精通的PyTorch使用教程 2.1 入門階段 2.1.1 環境安裝與配置 2.1.2 Tensor基礎操作 2.1.3 自動求導&#xff08;Autograd&#xff09; 2.1.4 構建神經網絡&#xff08;nn模塊&#xff09; 2.1.5 …

系統架構設計師:設計模式——創建型設計模式

一、創建型設計模式 創建型模式抽象了實例化過程&#xff0c;它們幫助一個系統獨立于如何創建、組合和表示它的那些對象。一個類創建型模式使用繼承改變被實例化的類&#xff0c;而一個對象創建型模式將實例化委托給另一個對象。 隨著系統演化得越來越依賴于對象復合而不是類…

Dinero.js - 免費開源的 JavaScript 貨幣處理工具庫,完美解決 JS 浮點數精度丟失問題

今天介紹一個在前后端處理貨幣的工具庫&#xff0c;logo 很可愛&#xff0c;是一只藍色的招財小貓。 本文封面圖底圖來自免費 AI 圖庫 StockCake。 Dinero.js 是一個用于貨幣計算的 JavaScript 工具庫&#xff0c;解決開發者在金融、電商、會計等場景中處理貨幣時的精度丟失、…

HNUST湖南科技大學-嵌入式考試選擇題題庫(109道糾正詳解版)

HNUST嵌入式選擇題題庫 1.下面哪點不是嵌入式操作系統的特點。(B) A.內核精簡 B.功能強大 C.專用性強 D.高實時性 解析&#xff1a; 嵌入式操作系統特點是內核精簡、專用性強、高實時性&#xff0c;而"功能強大"通常指的是通用操作系統&#x…

【工具】Windows批量文件復制教程:用BAT腳本自動化文件管理

一、引言 在日常開發與部署過程中&#xff0c;文件的自動化復制是一個非常常見的需求。無論是在構建過程、自動部署&#xff0c;還是備份任務中&#xff0c;開發者經常需要將某個目錄中的 DLL、配置文件、資源文件批量復制到目標位置。相比使用圖形界面的復制粘貼操作&#xf…

xray-poc編寫示例

禁止未授權掃描和測試行為&#xff01;&#xff01;&#xff01; 1. SQL 時間盲注檢測 (Time-Based Blind SQLi) name: generic/time-based-sqli rules:- method: GETpath: "/product?id1 AND (SELECT 1 FROM (SELECT SLEEP(5))a)--"expression: |response.status…

【Day 14】HarmonyOS分布式數據庫實戰

一、分布式數據庫基礎 1. 核心概念速記表 術語解釋示例場景分布式數據庫數據自動同步到同賬號設備手機添加商品→平板立即顯示KV數據模型鍵值對存儲&#xff08;類似JSON&#xff09;{"cart_item1": {"name":"牛奶","price":10}}數據…

【數據結構】- 棧

前言&#xff1a; 經過了幾個月的漫長歲月&#xff0c;回頭時年邁的小編發現&#xff0c;數據結構的內容還沒有寫博客&#xff0c;于是小編趕緊停下手頭的活動&#xff0c;補上博客以洗清身上的罪孽 目錄 前言&#xff1a; 棧的應用 括號匹配 逆波蘭表達式 數制轉換 棧的實…

TDA4VM SDK J721E (RTOS/Linux) bootloaders梳理筆記

文章目錄 1. 前言2. RTOS BootLoader2.1 引導模式2.2 啟動序列2.2.1 流程框圖2.2.2 Memory map2.3 鏡像格式詳解3. Linux BootLoader鏡像格式詳解啟動流程參考1. 前言 TDA4VM的BootLoader包含兩部分:RTOS的和Linux的。 2. RTOS BootLoader 這是在SoC上的所有內核運行FreeRTO…

Spring Boot + MyBatis-Plus 的現代開發模式

之前的Maven項目和本次需要的環境配置并不一樣 之前使用的是&#xff1a; 傳統的 MyBatis 框架&#xff08;非 Spring Boot 環境&#xff09; 手動管理 SqlSession 使用了 .xml 的 Mapper 映射文件 沒有 Spring 容器管理&#xff08;沒有 Service / RestController 等&…

【Quest開發】極簡版!透視環境下摳出身體并能遮擋身體上的服裝

前兩天發了一個很復雜的版本&#xff0c;又鼓搗了一下發現完全沒有必要。我之前的理解有點偏&#xff08;不是錯誤的但用法錯了&#xff09;&#xff0c;但是有一些小伙伴收藏了&#xff0c;害怕里面的某些東西對誰有用&#xff0c;所以寫了一篇新的&#xff0c;前兩步配置環境…

vue 常見ui庫對比(element、ant、antV等)

Element UI 1. 簡介 Element UI 是一個基于 Vue 2 和 Vue 3 的企業級 UI 組件庫&#xff0c;提供了豐富的組件和主題定制功能。官方網站&#xff1a;Element UI 2. 主要特點 豐富的組件&#xff1a;包括表單、表格、布局、導航、彈窗等多種組件。主題定制&#xff1a;支持主…

MATLAB畫一把傘

% 傘的參數num_ribs 5; % 傘骨數量修改為5R 1; % 傘的半徑height 0.5; % 傘的高度handle_length 2; % 傘柄長度semicircle_radius 0.26; % 傘柄末端半圓的半徑% 生成傘葉網格theta linspace(0, 2*pi, 100);phi linspace(0, pi/2, 50);[Theta, Phi] meshgrid(theta, phi…

如何在 Go 中實現各種類型的鏈表?

鏈表是動態內存分配中最常見的數據結構之一。它由一組有限的元素組成&#xff0c;每個元素&#xff08;節點&#xff09;至少占用兩塊內存&#xff1a;一塊用于存放數據&#xff0c;另一塊用于存放指向下一個節點的指針。本文教程將說明在 Go 語言中如何借助指針和結構體類型來…

新一代機載相控陣雷達的發展

相控陣雷達以其優越的性能在軍事領域中有著廣闊的應用前景&#xff0c;但由于復雜的技術、昂貴的造價使其應用范圍還存在一定的局限性。然而&#xff0c;國內外對相控陣技術的研究非常重視&#xff0c;并取得了豐碩的成果。 軍用相控陣雷達主要分為陸基、海基和空基幾種類型。 …

多數元素題解(LC:169)

169. 多數元素 核心思想&#xff08;Boyer-Moore 投票算法&#xff09;&#xff1a; 解題思路&#xff1a;可以使用 Boyer-Moore 投票算法、該算法的核心思想是&#xff1a; 維護一個候選元素和計數器、初始時計數器為 0。 遍歷數組&#xff1a; 當計數器為 0 時、設置當前元…

數據庫 AI 助手測評:Chat2DB、SQLFlow 等工具如何提升開發效率?

一、引言:數據庫開發的 “效率革命” 正在發生 在某互聯網金融公司的凌晨故障現場,資深 DBA 正滿頭大汗地排查一條執行超時的 SQL—— 該語句涉及 7 張核心業務表的復雜關聯,因索引缺失導致全表掃描,最終引發交易系統阻塞。這類場景在傳統數據庫開發中屢見不鮮:據 Gartne…

【中間件】bthread效率為什么高?

bthread效率為什么更高&#xff1f; 1 基本概念 bthread是brpc中的用戶態線程&#xff08;也可稱為M:N線程庫&#xff09;&#xff0c;目的是&#xff1a;提高程序的并發度&#xff0c;同時降低編碼難度&#xff0c;在多核cpu上提供更好的scalability和cache locality。其采用…

DeepSeek V2:引入MLA機制與指令對齊

長上下文革命:Multi-Head Latent Attention(MLA)機制 傳統 Transformer 的多頭注意力需要緩存所有輸入token的 Key 和 Value,這對長文本推理時的內存開銷極為龐大。DeepSeek V2 針對這一難題提出了“Multi-Head Latent Attention”(MLA)機制。MLA 的核心思想是對多頭注意…

Druid監控sql導致的內存溢出--內存分析工具MemoryAnalyzer(mat)

問題 druid監控sql在網頁端顯示&#xff0c;我的服務插入sql比較大&#xff0c;druid把執行過的sql保存在DruidDataSource類的成員變量JdbcDataSourceStat dataSourceStat&#xff1b; JdbcDataSourceStat類中的LinkedHashMap<String, JdbcSqlStat> sqlStatMap中&#…