算法學習day10(貪心算法)

貪心算法:由局部最優->全局最優

貪心算法一般分為如下四步:

  • 將問題分解為若干個子問題
  • 找出適合的貪心策略
  • 求解每一個子問題的最優解
  • 將局部最優解堆疊成全局最優解

一、擺動序列(理解難)

連續數字之間的差有正負的交替,則序列稱為擺動序列。返回的nums值是擺動序列中元素的個數

  • 例如,?[1, 7, 4, 9, 2, 5]?是一個?擺動序列?,因為差值?(6, -3, 5, -7, 3)?是正負交替出現的。

  • 相反,[1, 4, 7, 2, 5]?和?[1, 7, 4, 5, 5]?不是擺動序列,第一個序列是因為它的前兩個差值都是正數,第二個序列是因為它的最后一個差值為零。

思路:將數組想象成一個上上下下的圖表,定義curDiff=nums[i]-nums[i-1];和preDiff=nums[i+1]-nums[i];

考慮數組兩端 :?假設在數組開頭元素再添加一個相同的元素(或者初始化preDiff==0),這樣在遍歷第一個元素的時候,就不會發生數組越界問題。if(preDiff>=0&&curDiff<0||preDiff<=0&&curDiff>0)

前者對應的是先上再下,后者對應的是先下(可能為平坡)再上

考慮到末尾元素,直接讓result=1(默認最右邊有一個峰值)

單調坡度有平坡:?

不是每一次遍歷都要更新preDiff的值,而是當遇到峰值,前后波動的時候才去更新preDiff的值(為什么?);

代碼:

class Solution {public int wiggleMaxLength(int[] nums) {// 根據nums的長度剪枝if (nums.length <= 1)return nums.length;// 定義preDiff 和 curDiff 根據循環加resultint preDiff = 0;int curDiff = 0;int result = 1;// 把最后的元素看成一個峰值 直接+1for (int i = 0; i < nums.length - 1; i++) {curDiff = nums[i + 1] - nums[i];if (preDiff <= 0 && curDiff > 0 || preDiff >= 0 && curDiff < 0) {result++;// 遇到峰值 前后波動preDiff = curDiff;}}return result;}
}

二、最大子序和(貪心法/dp)

貪心法:

由局部最優推導出全局最優:連續和變為負數,下一個元素就不要加連續和。連續和為正數再加。

count+=nums[i] if(count>result)result=count; if(count<0)count=0;

代碼:

    public int maxSubArray(int[] nums) {int result=Integer.MIN_VALUE;int count=0;for(int i=0;i<nums.length;i++){count+=nums[i];if(count>result)result=count;if(count<0)count=0;}return result;}
Dp(動態規劃):

dp[i]:表示以從0->i這段集合的最大值。

dp[i]=Math.max(dp[i-1]+nums[i],nums[i])。eg:以3為下標,如果dp[2]為負數那肯定不加,加上拖后腿。如果dp[i-1]為正數,那肯定加。

代碼:

class Solution {public int maxSubArray(int[] nums) {int ans = Integer.MIN_VALUE;int[] dp = new int[nums.length];//dp[0]和nums[0]相等dp[0] = nums[0];ans = dp[0];for (int i = 1; i < nums.length; i++){dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);ans = Math.max(dp[i], ans);}return ans;}
}

三、買賣股票的最佳時機(一次遍歷)

暴力法搜索的話會超時異常

所以使用一次遍歷:每次遍歷到下標為i的元素時,就更新minprice。然后計算出在該天賣出,可以賺多少錢。

之前的思想是:如果在今天買,什么時候賣可以賺更多的錢。

現在的思想:如果今天賣,什么時候買可以賺更多錢。那我們就計算出今天之前的最小值,然后在那天買,今天賣,就可以找出最大利潤。

代碼:

class Solution {public int maxProfit(int[] prices) {int minprice = Integer.MAX_VALUE;int maxprofit = 0;for (int i = 0; i < prices.length; i++) {if (prices[i] < minprice) {minprice = prices[i];} else if (prices[i] - minprice > maxprofit) {maxprofit = prices[i] - minprice;}}return maxprofit;}
}

四、買賣股票的最佳時機II

給你一個整數數組?prices?,其中?prices[i]?表示某支股票第?i?天的價格。

在每一天,你可以決定是否購買和/或出售股票。你在任何時候?最多?只能持有?一股?股票。你也可以先購買,然后在?同一天?出售。返回?你能獲得的?最大?利潤。

?要求最大利潤->就要求從第二天開始每一天的利潤。

局部利潤最大->全局利潤最大

代碼:

class Solution {public int maxProfit(int[] prices) {int sumProfit=0;for(int i=1;i<prices.length;i++){if(prices[i]-prices[i-1]>0){sumProfit+=prices[i]-prices[i-1];}}return sumProfit;}
}

五、跳躍游戲(回溯/貪心)

回溯法:

寬度為nums[i]的大小,表示可以最大跳多遠。for(int i=1;i<=nums[i]);i++)

深度就是跳到最后一個元素所經歷的節點個數。

返回值:boolean;參數:int[] nums,int startIndex,boolean[] used

終止條件:當startIndex==nums.length-1的時候,代表已經跳到了最后一個元素。如果>的話就跳超了,直接return false;

單層遞歸邏輯:

1.首先判斷該點是不是遇到過(去重)if(used[startIndex]==true)return false;

2.然后使用一個boolean的變量接收下一層遍歷的返回值,如果下一層返回true,那么這一層也返回true。如果下一層返回false,說明下一個不行,直接used[i+startIndex]=true

代碼:

class Solution {public boolean canJump(int[] nums) {if (nums.length == 1)return true;// 只有一個元素的時候boolean[] used = new boolean[nums.length];return backTracking(nums, 0, used);}public boolean backTracking(int[] nums, int startIndex, boolean[] used) {if (startIndex == nums.length - 1)return true;if (startIndex > nums.length - 1)return false;if (used[startIndex])return false;// 之前已經來過這個下標位置 已經試過這種情況了 就直接返回falsefor (int i = 1; i <= nums[startIndex]; i++) {boolean flag = backTracking(nums, startIndex + i, used);if (flag == true) {return true;} else {used[startIndex + i] = true;}}used[startIndex] = true;return false;}
}
貪心法:

將跳躍問題->范圍覆蓋問題,如果在某點上,位置覆蓋到nums.length-1,那么就說明可以跳到最后一個位置,返回true;

在每次coverRange的范圍里面,去更新coverRange的范圍。coverRange=Math.max(coverRange,i+nums[i]);

if(coverRange>=nums.length-1)。為什么是>=而不是==。因為如果是>=的話,最后一個節點在我跳躍的范圍里面。

代碼:


class Solution {public boolean canJump(int[] nums) {if(nums.length==1)return true;int coverRange=0;//覆蓋的范圍是元素的下標 所以下面的for循環可以使用=for(int i=0;i<=coverRange;i++){coverRange=Math.max(coverRange,i+nums[i]);if(coverRange>=nums.length-1)return true;}return false;}
}

六、跳躍游戲II(貪心)在上一道題的基礎上求最小跳躍次數

給定一個長度為?n?的?0 索引整數數組?nums。初始位置為?nums[0]

每個元素?nums[i]?表示從索引?i?向前跳轉的最大長度。

返回到達?nums[n - 1]?的最小跳躍次數。生成的測試用例可以到達?nums[n - 1]

思路:整體最優解:在一個范圍里面,每次都往最遠的跳。方式:在0->cur這個范圍里面,找到下一次可以跳躍到的最遠距離,next=Math.max(next,i+nums[i]);

如果cur!=nums.length-1,說明還沒有到達終點,那我們就要cur=next(改變范圍),并且result++

如果next==nums.length,result++然后跳

代碼:

class Solution {public int jump(int[] nums) {if(nums.length<=1)return 0;// 定義變量 cur next resultint cur = 0, next = 0, result = 0;for (int i = 0; i < nums.length; i++) {// 每次都更新一個范圍里下次能跳到的最遠距離next = Math.max(i + nums[i], next);if(next>=nums.length-1){result++;break;}   if(i==cur){result++;cur=next;}}return result;}
}

? 七、K次取反后最大化的數組和

貪心策略的選擇:

1.如果有負數的話,先對絕對值更大的負數進行取反,直到k為0;

2.如果所有的負數都取反完后,k不為0并且為奇數,就對最小的非負數進行取反。如果k為偶數,不用變。

注意:將數組從小到大排序之后,負數取反的值可能比之前的正數小,所以在取反并且k!=0后,要將數組再次排序。

代碼:

class Solution {public int largestSumAfterKNegations(int[] nums, int k) {Arrays.sort(nums);//先對nums進行排序int startK=k;for(int i=0;i<nums.length;i++){if(nums[i]<0&&k>0){nums[i]*=-1;k--;}}//如果k不為0并且k為一個奇數,就選擇一個最小的正數去抵消它if(k%2!=0){Arrays.sort(nums);nums[0]*=-1;}return sumOfArr(nums);}public  int sumOfArr(int[] nums){int sum=0;for(int i:nums){sum+=i;}return sum;}
}

八、加油站(貪心)

卡爾哥的思路:一個加油站可以a升,但是去下一個加油站要消耗b升,一個加油站可以獲取/消耗的油為(a-b),

1.使用變量curSum將它們累加起來,如果curSum<0,就說明汽油不夠到達下一個加油站。那么此時將curSum置為零(i也會從下一個開始),

2.再使用一個變量totalSum將所有加油站的盈余都加起來,如果<0,就說明無論從哪一個起點開始都無法回到起點。

代碼:

class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {int gasSum=0;int totalSum=0;int index=0;for(int i=0;i<gas.length;i++){gasSum+=gas[i]-cost[i];//當前的累積量 如果<0 說明以i為起點的 無法循環totalSum+=gas[i]-cost[i];//總的累積量 如果<0 絕對找不到一個起點if(gasSum<0){index=(i+1)%gas.length;gasSum=0;}}if(totalSum<0)return -1;return index;}
}

九、分發糖果(貪心法)

n?個孩子站成一排。給你一個整數數組?ratings?表示每個孩子的評分。

  • 每個孩子至少分配到?1?個糖果。
  • 相鄰兩個孩子評分更高的孩子會獲得更多的糖果。

請你給每個孩子分發糖果,計算并返回需要準備的?最少糖果數目?。

問題:一個孩子所分發的糖果是由兩邊人共同影響的。eg:2 5 3? 2 。所分的糖果為1,2 但是第三個位置就不知道怎么確定了。

思路:先從左邊遍歷,再從右邊遍歷,遍歷到相同的位置要取最大值(因為同時要滿足兩個)

代碼:

class Solution {public int candy(int[] ratings) {int[] candies=new int[ratings.length];//首先我們從左往右遍歷candies[0]=1;for(int i=1;i<ratings.length;i++){if(ratings[i]>ratings[i-1])candies[i]=candies[i-1]+1;else candies[i]=1;}//我們從右往左遍歷for(int i=ratings.length-2;i>=0;i--){if(ratings[i]>ratings[i+1]){candies[i]=Math.max(candies[i],candies[i+1]+1);}}return sumOfArr(candies);}public int sumOfArr(int[] candies){int sum=0;for(int i:candies){sum+=i;}return sum;}
}

十、檸檬水找零(暴力)

暴力法:對bills[i]進行分情況判斷,==5/==10/==20。使用一個map集合當做錢包

1.等于5的時候,直接往map集合中添加

2.等于10的時候,先判斷5的是否>=1,然后更新一下5和10的數量

3.等于20的時候,優先使用5和10的進行支付,然后選擇三個5的進行支付。(因為5還要去支付10的)

代碼:

class Solution {public boolean lemonadeChange(int[] bills) {//使用一個map集合存錢Map<Integer, Integer> map = new HashMap();map.put(5,0);map.put(10,0);for (int i = 0; i < bills.length; i++) {if (bills[i] == 5) map.put(5, map.get(5) + 1);else if (bills[i] == 10) {if (map.get(5) >= 1) {map.put(5, map.get(5) - 1);map.put(10, map.get(10) + 1);} else {return false;}} else if (bills[i] == 20) {if(map.get(10)>0&&map.get(5)>0){map.put(10,map.get(10)-1);map.put(5,map.get(5)-1);}else if(map.get(5)>=3){map.put(5,map.get(5)-3);}else{return false;}}}return true;}
}

十一、根據身高重建隊列(貪心)

Arrays.sort()函數中可以自定義一個comparator規則,一般使用Lambda表達式簡化書寫(我感覺可讀性不高)。

匿名內部類:(當我們只需要用一次的時候,就不需要再創建一個類,而是通過匿名內部類來實現)

例如:

public class Demo {public static void main(String[] args) {//創建匿名內部類,直接重寫父類的方法,省去了創建子類繼承,創建子類對象的過程Fu fu= new Fu(){@Overridepublic void method() { //重寫父類method方法super.method();}};fu.method();   //調用method方法}

思路:將people[][]二維數組,通過Arrays.sort()排序。排序規則為:根據身高h排,即people[i][0]。

如果身高相等那么,根據前面的人:people[i][1]來排,升序排

第一種是普通的寫法/第二種是使用lambda表達式簡化開發

        Arrays.sort(people, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {if(o1[0]==o2[0])return o1[1]-o2[1];return o2[0]-o1[0];}});
        Arrays.sort(people,((o1, o2) -> {if(o1[0]==o2[0])return o2[1]-o2[0];return o2[0]-o1[0];//降序排}));

排序好之后,根據people[i][k]來進行排序,k為多少就插到下標為多少的位置。

java中的集合直接封裝好了add(int index,T element)方法;

add(peo[1],peo);

代碼:

    public int[][] reconstructQueue(int[][] people) {Arrays.sort(people,(a,b)->{if(a[0]==b[0])return a[1]-b[1];//如果身高相同 就比k k越小應該在越前面 所以是a-breturn b[0]-a[0];//降序排 是b-a});LinkedList<int[]> queue=new LinkedList<>();for(int[] peo:people){queue.add(peo[1],peo);}return queue.toArray(new int[people.length][]);}

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

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

相關文章

Maven Nexus3 私服搭建、配置、項目發布指南

maven nexus私服搭建 訪問nexus3官方鏡像庫&#xff0c;選擇需要的版本下載&#xff1a;Docker Nexus docker pull sonatype/nexus3:3.49.0 創建數據目錄并賦權 sudo mkdir /nexus-data && sudo chown -R 200 /nexus-data 運行(數據目錄選擇硬盤大的卷進行掛載) …

mysql快速精通(五)數據庫備份與還原

主打一個實用 對于重要數據我們常常進行備份以應對突發情況&#xff0c;以下使用Navicat對數據進行備份&#xff0c;想了解sql語句的自尋 備份?? 還原??

自動化回復信息工具的開發分享!

在當今信息爆炸的時代&#xff0c;無論是個人還是企業&#xff0c;都面臨著大量的信息處理和回復工作&#xff0c;為了提高效率&#xff0c;自動化回復信息工具變得越來越重要。 本文旨在分享一個簡單但實用的自動化回復信息工具的五段源代碼開發過程&#xff0c;幫助讀者理解…

DNS正向解析,反向解析

目錄 一、正向解析 1.下載DNS軟件包 2.修改主配置文件 3.創建區域文件 4.配置DNS 5.測試 二、反向解析 1.修改主配置文件 2.創建區域文件 3.測試 一、正向解析 1.下載DNS軟件包 [rootwww ~]# yum indtall -y bind注意&#xff1a; 下載軟件前需要配置倉庫&…

DolphinScheduler本地安裝部署與遠程任務調度管理實踐應用

文章目錄 前言1. 安裝部署DolphinScheduler1.1 啟動服務 2. 登錄DolphinScheduler界面3. 安裝內網穿透工具4. 配置Dolphin Scheduler公網地址5. 固定DolphinScheduler公網地址 前言 本篇教程和大家分享一下DolphinScheduler的安裝部署及如何實現公網遠程訪問&#xff0c;結合內…

自動駕駛AVM環視算法--540度全景的算法實現和exe測試demo

參考&#xff1a;金書世界 540度全景影像是什么 540度全景影像是在360度全景影像基礎上的升級功能&#xff0c;它增加了更多的攝像頭來收集周圍的圖像數據。通常&#xff0c;這些攝像頭分布在車輛的更多位置&#xff0c;例如車頂、車底等&#xff0c;以便更全面地捕捉車輛周圍…

無人機游學技術及前景分析

一、技術概述 無人機&#xff0c;即無人駕駛飛行器&#xff0c;通過遠程控制或自主飛行控制系統進行操作。隨著科技的快速發展&#xff0c;無人機技術日益成熟&#xff0c;不僅廣泛應用于軍事偵察、打擊等領域&#xff0c;也逐漸滲透到民用市場&#xff0c;包括農業植保、影視…

PostgreSQL17索引優化之支持并行創建BRIN索引

PostgreSQL17索引優化之支持并行創建BRIN索引 最近連續寫了幾篇關于PostgreSQL17優化器改進的文章&#xff0c;其實感覺還是挺有壓力的。對于原理性的知識點&#xff0c;一方面是對這些新功能也不熟悉&#xff0c;為了盡可能對于知識點表述或總結做到準確&#xff0c;因此需要…

華為認證試題有題庫嗎?華為認證題庫怎么領取?

在競爭激烈的就業環境下&#xff0c;若你擁有華為認證將可以提高個人綜合能力&#xff0c;更好的適應行業變化。相信大家都有聽說過想考取華為初級認證并不困難&#xff0c;因為它有專門的題庫供考生備考。 那么&#xff0c;到底華為認證試題有題庫嗎?華為認證題庫要怎么領取…

java并發編程之美-第1章 并發編程線程基礎-線程的創建與運行

文章目錄 1.什么是線程2. 線程創建和運行 1.什么是線程 進程是操作系統進行資源分配和調度的基本單位&#xff0c;線程是 CPU 分配的基本單位。 程序計數器用來記錄線程當前要執行的指令地址。CPU一般是使用時間片輪轉方式讓線程輪詢占用的&#xff0c;程序計數器是記錄線程…

【Django】報錯‘staticfiles‘ is not a registered tag library

錯誤截圖 錯誤原因總結 在django3.x版本中staticfiles被static替換了&#xff0c;所以這地方換位static即可完美運行 錯誤解決

callBack方式實現threejs點擊事件Raycaster

我用的的示例類發方式來初始化場景。 類里面定義點擊方法。 initMouse(fun) {window.addEventListener("click", (event) > {this.clickObject(event, fun);});}// 鼠標事件clickObject(event, fun) {// 計算點擊位置的歸一化設備坐標const mouse new THREE.Ve…

IO模型理論學習

1、什么是IO 計算機視角下的io AIO

“泰迪·曲靖師范學院數學與統計學院數據科學教學實訓平臺”工作室簽約揭牌儀式圓滿結束

為深化校企合作&#xff0c;實現應用型人才培養目標。泰迪智能科技攜手曲靖師范學院數學與統計學院共建“數據科學教學實訓平臺工作室”。 2024年7月10日&#xff0c;“?泰迪數學與統計學院數據科學教學實訓平臺”工作室揭牌儀式在曲靖師范學院舉行。泰迪智能科技昆明分公司院…

LPRNet 車牌識別部署 rk3588(pt-onnx-rknn)包含各個步驟完整板端代碼

雖然車牌識別技術很成熟了&#xff0c;但完全沒有接觸過。一直想搞一下、整一下、試一下、折騰一下&#xff0c;工作之余找了一個簡單的例子入個門。本博客簡單記錄一下 LPRNet 車牌識別部署 rk3588流程&#xff0c;訓練參考 LPRNet 官方代碼。 1、導出onnx ??導出onnx很容易…

EtherCAT設備配置:SCI EoeMacIp 文件與實際設備配置的比較過程

標題&#xff1a;EtherCAT設備配置&#xff1a;SCI文件與實際設備配置的比較過程 在工業自動化領域&#xff0c;EtherCAT&#xff08;Ethernet for Control Automation Technology&#xff09;作為一種高效的實時以太網協議&#xff0c;正在被廣泛應用。在EtherCAT網絡的配置過…

SW - 將面導出為dxf

文章目錄 SW - 將面導出為dxf概述筆記原點問題END SW - 將面導出為dxf 概述 在做PCB板框. 以前做過一個筆記&#xff0c;用autoCAD來制作導出dxf(cadence SPB17.4 - 用autoCAD2022畫一個PCB板框)。 不喜歡用autoCAD&#xff08;相對麻煩&#xff09;, 還是喜歡用SW&#xff0…

異步日志:性能優化的金鑰匙

一、背景 2024 年 4 月的一個寧靜的夜晚&#xff0c;正當大家忙完一天的工作準備休息時&#xff0c;應急群里“咚咚咚”開始報警&#xff0c;提示我們余利寶業務的贖回接口成功率下降。 通過 Monitor 監控發現&#xff0c;該接口的耗時已經超過了網關配置的超時閾值(2s)&#…

Spring Cloud Alibaba整合Seata實戰

Spring Cloud Alibaba整合Seata實戰 1.啟動Seata Server 1.1 環境準備 1&#xff09;指定nacos作為配置中心和注冊中心 修改registry.conf文件 注意&#xff1a;客戶端配置registry.conf使用nacos時也要注意group要和seata server中的group一致&#xff0c;默認group是&quo…

我的PHP8編譯日志

編譯命令在arm和x86架構上是一樣的&#xff0c;如果缺少依賴庫&#xff0c;按需要安裝&#xff1a; 登錄后復制 yuminstall libcurl libcurl-devel yum install openssl openssl-devel yum install pcre2 pcre2-devel yum install libxml2 libxml2-devel 1.2.3.4. 配置和編譯&…