基礎貪心算法集合2(10題)

目錄

1.單調遞增的數字

2.壞了的計算器

?3.合并區間

4.無重疊區間

5. 用最少數量的箭引爆氣球

?6.整數替換

解法1:模擬+記憶化搜索

解法2位運算+貪心

7.俄羅斯套娃信封問題

補充.堆箱子

8.可被3整除的最大和

?9.距離相等的條形碼

?10.重構字符串


1.單調遞增的數字

?738. 單調遞增的數字 - 力扣(LeetCode)

但是如果只這么處理會出現bug?

例如如下這種情況,我們需要找到最前面的5.

因此

class Solution {
public:int monotoneIncreasingDigits(int n) {string num = to_string(n);int sz = num.size();int i = 0;while(i+1 < sz && num[i] <= num[i+1])i++;if(i+1 == sz)return n;//如果全遞增直接返回,或者處理nums[i]的時候判斷一下while(i - 1 >= 0 && num[i-1] == num[i])i--;num[i]--;for(int k = i + 1; k < sz; k++){num[k] = '9';}return stoi(num);//std::stoi 會忽略前導零,只返回字符串表示的整數值}
};

2.壞了的計算器

?991. 壞了的計算器 - 力扣(LeetCode)

看到這題我們首先就想到正向推導。

我們貪心地想到,如果想讓初始數字以盡可能少的次數變成目標數字,可以多用*2操作。

但是我們發現這種貪心是不對的,對于*2和-1的操作,判斷標準不是很明確。?用正向的方法比較難解決這個問題

????????于是我們想到正難則反,而*2 和-1的操作正好有相反的/2和+1操作。?

????????這一題有個非常重要的點就是它里面的數據是沒有小數的,從起始數據到目標數據,不斷*2,-1操作下是不能產生小數的。

? ? ? ? ? 所以我們在面對奇數的時候,就不能進行/2操作了,只能進行+1操作。

整理思路,我們得出以下結論:

1.當end <= begin

當?end <= begin時,end要想達到begin,肯定不可能進行/2操作,只能進行+1操作,這時候無論奇數偶數,都只有+1的選擇。我們需要進行begin-end次操作

?2.當end > begin 的時

當end > begin 的時候

?我們如果想要先+1再/2,那么我們必須要加偶數個1,我們才能/2.最后,我們通過k+1次操作得到了(x+k)/2.

而如果我們先/2,那么我們只需要1+k/2 次就能得到(x+k)/2。

我們很容易得到先進行除法是更優的。

因此在end > begin的時候 ,我們奇數仍然是只能+1,偶數則是只進行/2操作

class Solution {
public:int brokenCalc(int startValue, int target) {int ret = 0;while(target > startValue){if(target % 2 == 0){target /= 2;ret++;}else{target++;ret++;}}ret += startValue - target;return ret;}
};

?3.合并區間

56. 合并區間 - 力扣(LeetCode)

區間問題解法

我們為了思路統一,統一采用左端點排序

?假設我們有一個區間,從left 到right

那么我們下一個區間有以下這些情況。

整體分為有重疊部分和沒有重疊部分。

當有重疊部分時,我們保存左端點,取較大的右端點。(因為進行排序后,左端點是升序排序的)

當沒有重疊部分時,我們把{left,right}加入ret數組,然后更新left和right。

class Solution {
public:static bool cmp(vector<int> a, vector<int> b){return a[0] < b[0];}vector<vector<int>> merge(vector<vector<int>>& intervals) {//排序sort(intervals.begin(), intervals.end(), cmp);//合并區間vector<vector<int>> ret;int left = intervals[0][0];int right = intervals[0][1];for(int i = 1; i < intervals.size(); i++){if(intervals[i][0] <= right)//有重疊部分{right = max(right,intervals[i][1]);//合并}else//無重疊{ret.push_back({left, right});//加入到結果中left = intervals[i][0];right = intervals[i][1];}}ret.push_back({left, right});return ret;}
};

4.無重疊區間

?435. 無重疊區間 - 力扣(LeetCode)

?

仍然是先按照左端點排序。

我們要移除最少的區間,那也就是說要保留更多的區間。

因此我們可以采用以下策略來保留更多區間。

當存在區間重疊時,我們保留較小的右端點,這樣它和后面的?區間有重疊的可能性就會變小。

當區間無重疊,我們更新left right并把count++即可。

遍歷數組結束后要記得加上最后存在left right里面的那段區間。

最后,因為我們求的是移除的區間,因此把數組的長度減去count就是我們的返回值

class Solution {
public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {int count = 0;sort(intervals.begin(), intervals.end());int left = intervals[0][0];int right = intervals[0][1];for(int i = 1; i < intervals.size(); i++){if(intervals[i][0] < right){right = min(right,intervals[i][1]);}else{count++;left = intervals[i][0];right = intervals[i][1];}}count ++;return intervals.size() - count;}
};

5. 用最少數量的箭引爆氣球

452. 用最少數量的箭引爆氣球 - 力扣(LeetCode)

理解題意,我們發現這也是一個區間問題。

我們發現這題找的實際上是交集。

??

class Solution {
public:int findMinArrowShots(vector<vector<int>>& points) {sort(points.begin(), points.end());int cover = 0;int right = points[0][1];for(int i = 1; i < points.size(); i++){if(points[i][0] <= right)//和上一個區間有交集{cover++;//重疊部分++right = min(right, points[i][1]);//右端點較小的同時也是是重疊區間的右端點}else{right = points[i][1];//無交集,以新的區間為基準再求重疊部分}}return points.size() - cover;}
};

?6.整數替換

解法1:模擬+記憶化搜索

就是暴力枚舉每種情況,對于偶數直接除以2,對于奇數則是取?min(hash[n-1], hash[n+1])

需要注意的地方是,為了防止INT_MAX + 1 溢出,我們dfs函數的類型使用long long,哈希表也是一樣。

class Solution {
public:unordered_map<long long, int> hash;int integerReplacement(int n) {return dfs(n);}int dfs(long long n){if(n == 1)return 0;if(n % 2 == 0){if(!hash.count(n/2)){hash[n/2] = dfs(n/2);}return 1 + hash[n/2];}else{if(!hash.count(n+1) ){hash[n+1] = dfs( n+1 );}if(!hash.count( n-1 ) ){hash[ n-1 ] = dfs( n-1 );}return 1  + min(hash[n-1], hash[n+1]);}}
};

解法2位運算+貪心

對于偶數我們進行/2操作即可。

對于奇數操作, 當其為01結尾的時候,我們采用-1操作操作數會更少。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 當其為11結尾的時候,-1操作會使得一位1變為0,而+1操作可能會使得多于一位的1變為0,因此采用+1的操作會更快捷地得到最終值。

最后有一個例外,即3,我們應該采用-1操作。

要判斷最后兩位是01還是11,我們只需要把這些數對4取余即可,看余數是1還是3即可判斷。

這道題的貪心就貪在不同的奇數是+1還是-1,已經在過程中證明好了

?同樣需要加一個longlong

class Solution {
public:int integerReplacement(int num) {int ret = 0;long long n = num;while(n > 3){if(n % 2 == 0){ret++;n  = n >> 1;}else{if(n % 4 == 3){n = n + 1;ret++;}else if(n % 4 == 1){n = n - 1;ret++;}}}if(n == 3)return ret + 2;else if(n == 2)return ret + 1;else return ret;}
};

7.俄羅斯套娃信封問題

?解法1:區間排序+動態規劃(超時)

解法2:區間排序 + 貪心 + 二分

我們嚴格按照左端點排序后,實際上已經不用看左端點了,因為總是遞增的。?

那么這道題經過這樣處理,就變成了一個最長遞增子序列問題。

?

????????但是當左端點有重復的時候需要注意,這時候如果我們的右端點按照升序排,我們就會把一些不該加的元素加入。

?????????這時候就需要我們在左端點相同的時候把右端點降序排序

?

????????這樣的好處是,我們就不會有可能把這些數字全部接到原數組后面了。因為如果有更小的數,那么我們會將其與原來的數替換。例如上一個數是3,按照升序排序的話,4679都會排到它后面。

????????可是如果我們降序,則我們在將9加入數組后,后面的764都只是更新數組末尾的9而已,讓9不斷被替換為764.

class Solution {
public:static bool cmp(const vector<int> & a, const vector<int> & b){if(a[0] != b[0])return a[0] < b[0];else return a[1] > b[1];}int maxEnvelopes(vector<vector<int>>& env) {sort(env.begin(), env.end(), cmp);vector<int> ret;ret.push_back(env[0][1]);for(int i = 1; i < env.size(); i++){if(env[i][1] > ret.back()){ret.push_back(env[i][1]);}else{int left = 0; int right = ret.size() - 1;while(left < right){int mid = left + (right-left) / 2;if( env[i][1] <= ret[mid]){right = mid;}else{left = mid + 1;}}ret[left] = env[i][1];}}return ret.size();}
};

補充.堆箱子

?雖然俄羅斯套娃信封中的解法1會超時,但是在堆箱子這題中是可以通過的

面試題 08.13. 堆箱子 - 力扣(LeetCode)

?排序后的思路和最長遞增子序列相同

有兩個需要注意的問題

class Solution {
public:static bool cmp(vector<int> a, vector<int> b){return a[0] < b[0];}int pileBox(vector<vector<int>>& box) {sort(box.begin(), box.end(),cmp);//1.需要自己手動寫一個排序函數,按照某一維度來排。 //默認排序會出問題int n = box.size();if(n == 0)return 0;vector<int> dp(n , 0);for(int i = 0; i < n; i++)//2.初始化dp表的時候,每個箱子最小的堆疊高度是自己的高度{dp[i] = box[i][2];}int ret = dp[0];for(int i = 1; i < n; i++){for(int j = i - 1; j >= 0; j--){if(box[j][0] < box[i][0] && box[j][1] < box[i][1] && box[j][2] < box[i][2]){dp[i] = max(dp[i], dp[j] + box[i][2]);}}ret = max(ret, dp[i]);}return ret;}
};

8.可被3整除的最大和

?1262. 可被三整除的最大和 - 力扣(LeetCode)

?

我們正難則反,根據累加和的不同情況,刪去一些數即可,而我們只需要貪心地刪除最小值即可。 ?

????????分類情況中,?我們把第二種情況拿來舉例子,可能我們有1個或者4個或者7個除以3余1的數,但是我們只需要取出最小的那個。整體來看是把這一組數分成兩塊,一塊是一個除以3余1的數,另一塊是可以被3整除的。

? ? ? ? 下面的另外三種也是一樣的分組方式。

? ? ? ? 但是我們要注意,這些情況有可能不會全都有,因此我們可以先將x1 x2 y1 y2等賦值為

10010(題目中數組元素最大為10000),這樣我們在最后取max的時候就必然不會取到無效情況。

?

更新最小值以及次小值只需要分類討論即可?

?

class Solution {
public:int maxSumDivThree(vector<int>& nums) {int sum = 0;int n = nums.size();for(int i = 0; i < n; i++){sum += nums[i];}if(sum % 3 == 0){return sum;}else if(sum % 3 == 1){int x1,y1,y2;x1 = y1 = y2 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 1){x1 = min(x1, tmp);}else if(tmp % 3 == 2){if(tmp <= y1){y2 = y1;y1 = tmp;}else if(tmp > y1 && tmp <= y2){y2 = tmp;}}}return max(sum - x1, sum - y1 - y2);}else//取余等于2{int x1,x2,y1;x1 = x2 = y1 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 2){y1 = min(y1, tmp);}else if(tmp % 3 == 1){if(tmp <= x1){x2 = x1;x1 = tmp;}else if(tmp > x1 && tmp <= x2){x2 = tmp;}}}return max(sum - x1 - x2, sum - y1);}}
};

?

class Solution {
public:int maxSumDivThree(vector<int>& nums) {int sum = 0;int n = nums.size();for(int i = 0; i < n; i++){sum += nums[i];}if(sum % 3 == 0){return sum;}else if(sum % 3 == 1){int x1,y1,y2;x1 = y1 = y2 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 1){x1 = min(x1, tmp);}else if(tmp % 3 == 2){if(tmp <= y1){y2 = y1;y1 = tmp;}else if(tmp > y1 && tmp <= y2){y2 = tmp;}}}return max(sum - x1, sum - y1 - y2);}else//取余等于2{int x1,x2,y1;x1 = x2 = y1 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 2){y1 = min(y1, tmp);}else if(tmp % 3 == 1){if(tmp <= x1){x2 = x1;x1 = tmp;}else if(tmp > x1 && tmp <= x2){x2 = tmp;}}}return max(sum - x1 - x2, sum - y1);}}
};

?9.距離相等的條形碼

?1054. 距離相等的條形碼 - 力扣(LeetCode)

?

如果出現最多的數超過(n+1)/2,那么必定有兩個相同元素會相鄰?

?

我們只需要把最大的那個元素先排好,然后去排其它的即可,我們的i如果越界,那么將其置為1即可?

class Solution {
public:vector<int> rearrangeBarcodes(vector<int>& barcodes) {int maxval = -1; int maxcount = 0;unordered_map<int, int> hash;for(auto ch : barcodes ){if( maxcount < ++hash[ch] ){maxval = ch;maxcount = hash[ch];}}int n = barcodes.size();int i;vector<int> ret(n);for(i = 0; i < n && maxcount > 0; i += 2){ret[i] = maxval;maxcount --;}hash.erase(maxval);for(auto& [x, y] : hash){for(int j = 0; j < y; j++){if(i >= n)i = 1;ret[i] = x;i += 2;}}return ret;}
};

?10.重構字符串

767. 重構字符串 - 力扣(LeetCode)?

????????這道題和上一道題是一模一樣的的,唯一的不同就是這道題可能無解,因此我們需要判斷一些maxcount 會不會大于(s.size()?+ 1)/2.?

class Solution {
public:string reorganizeString(string s) {int n = s.size();char maxval;int maxcount = 0;string ret = s;unordered_map<char, int> hash;for(auto ch: s){if(maxcount < ++hash[ch]){maxval = ch;maxcount = hash[ch];}}if(maxcount > (n + 1) / 2)return "";int i;for(i = 0; i < n && maxcount > 0; i += 2){ret[i] = maxval;maxcount--;}hash.erase(maxval);for(auto &[x, y] : hash){for(int j = 0; j < y; j++){if(i >= n)i = 1;ret[i] = x;i += 2;}}return ret;}
};

?

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

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

相關文章

RaabitMQ 快速入門

&#x1f389;歡迎大家觀看AUGENSTERN_dc的文章(o゜▽゜)o☆?? &#x1f389;感謝各位讀者在百忙之中抽出時間來垂閱我的文章&#xff0c;我會盡我所能向的大家分享我的知識和經驗&#x1f4d6; &#x1f389;希望我們在一篇篇的文章中能夠共同進步&#xff01;&#xff01;&…

語音識別——根據聲波能量、VAD 和 頻譜分析實時輸出文字

SenseVoiceSmall網絡結構圖 ASR(語音識別)是將音頻信息轉化為文字的技術。在實時語音識別中,一個關鍵問題是:如何決定將采集的音頻數據輸入大模型的最佳時機?固定時間間隔顯然不夠靈活,太短可能導致頻繁調用模型,太長則會延遲文字輸出。有沒有更智能的方式?答案是肯定…

AI大模型如何重塑科研范式:從“假說驅動”到“數據涌現”

??個人主頁??:慌ZHANG-CSDN博客 ????期待您的關注 ???? 一、引言:科研進入“模型共研”時代 傳統科研范式通常以“假設→實驗→驗證→理論”的方式推進,這一經典路徑建立在人類的認知能力與邏輯推理基礎上。然而,隨著數據規模的爆炸式增長與知識系統的高度復雜…

使用Python寫入JSON、XML和YAML數據到Excel文件

在當今數據驅動的技術生態中&#xff0c;JSON、XML和YAML作為主流結構化數據格式&#xff0c;因其層次化表達能力和跨平臺兼容性&#xff0c;已成為系統間數據交換的通用載體。然而&#xff0c;當需要將這類半結構化數據轉化為具備直觀可視化、動態計算和協作共享特性的載體時&…

面試題:Eureka和Nocas的區別

Eureka 與 Nacos 核心區別對比 一、功能定位與核心能力 ?維度??Eureka??Nacos??核心功能?專注服務注冊與發現&#xff0c;無配置管理功能?:ml-citation{ref“1,3” data“citationList”}集成服務注冊、發現、配置管理、動態DNS等?:ml-citation{ref“1,3” data“c…

2025年4月15日 百度一面 面經

目錄 1. 代理相關 從靜態代理到動態代理 2. cglib可以代理被final修飾的類嗎,為什么 3. JVM 體系結構 4. 垃圾回收算法 5. 什么是注解 如何使用 底層原理 6. synchronized和reentrantlock 7. 講一下你項目中 redis的分布式鎖 與java自帶的鎖有啥區別 8. post 請求和 ge…

AI改變生活

AI改變生活 人工智能&#xff08;AI&#xff09;在我們生活中的應用越來越廣泛&#xff0c;深刻地改變了我們的工作和生活方式。以下是一些AI實際應用的實例&#xff0c;以及它們如何影響我們的日常生活。 1. 智能助手 智能助手如Siri、Alexa和Google Assistant等&#xff0…

信奧賽之c++基礎(取模運算與數位分離)

?? 數字拆解大冒險——取模運算與數位分離魔法課 ?? 第一章:糖果分裝術——取模運算 ?? 分糖果游戲 7顆糖每人分3顆: 每人得到:7 / 3 = 2顆剩余糖果:7 % 3 = 1顆(%就是取模符號) 就像把糖果裝袋后剩下的零散糖粒!?? 取模運算說明書 算式比喻結果10 % 310顆糖分…

揭秘大數據 | 21、軟件定義計算

老夫先將這個小系列的前兩篇內容鏈接奉上&#xff0c;方便感興趣的朋友一氣讀之。 揭秘大數據 | 19、軟件定義的世界-CSDN博客 揭秘大數據 | 20、軟件定義數據中心-CSDN博客 今天&#xff0c;書接上文&#xff0c;開聊軟件定義計算的那些事兒&#xff01; 虛擬化是軟件定義…

FPGA-DDS技術的波形發生器

1.實驗目的 1.1掌握直接數字頻率合成&#xff08;DDS&#xff09;的基本原理及其實現方法。 1.2在DE2-115 FPGA開發板上設計一個可調頻率的正弦波和方波發生器&#xff0c;頻率范圍10Hz~5MHz&#xff0c;最小分辨率小于1kHz。 1.3使用Quartus II進行仿真&#xff0c;并通過S…

LeetCode[541]反轉字符串Ⅱ

思路&#xff1a; 題目給我們加了幾個規則&#xff0c;剩余長度小于2k&#xff0c;大于等于k就反轉k個&#xff0c;小于k就全部反轉&#xff0c;我們按照這個邏輯來就行。 第一就是大于等于k就反轉k個&#xff0c;我們for循環肯定是i2k了&#xff0c;接下來就是判斷是否大于等于…

實現定長的內存池

池化技術 所謂的池化技術&#xff0c;就是程序預先向系統申請過量的資源&#xff0c;然后自己管理起來&#xff0c;以備不時之需。這個操作的價值就是&#xff0c;如果申請與釋放資源的開銷較大&#xff0c;提前申請資源并在使用后并不釋放而是重復利用&#xff0c;能夠提高程序…

路由器原理與配置技術詳解

一、路由基礎原理 1.1 路由器的核心功能 網絡層設備&#xff1a;工作在OSI參考模型第三層&#xff0c;實現不同網絡間的互聯互通智能路徑選擇&#xff1a;基于路由表為數據包選擇最優傳輸路徑協議轉換&#xff1a;處理不同網絡接口間的協議差異&#xff08;如以太網與PPP&…

Leetcode 3518. Smallest Palindromic Rearrangement II

Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解題思路 這一題是題目Leetcode 3517. Smallest Palindromic Rearrangement I的升級版本&#xff0c;其主要的…

大模型——Crawl4AI 中的數據提取策略

大模型——Crawl4AI 中的數據提取策略 在本章中,將詳細介紹在 Crawl4AI 中可用的數據提取策略。這些策略包括: LLMExtractionStrategy:用于詳細內容提取。JsonCssExtractionStrategy:使用 CSS 選擇器進行結構化數據檢索。CosineStrategy:基于余弦相似性進行有效的語義分段…

職坐標解碼互聯網行業轉型發展新動能

當前&#xff0c;互聯網行業正以前所未有的速度重塑全球產業格局。工信部最新數據顯示&#xff0c;我國互聯網企業營收連續三年保持雙位數增長&#xff0c;其中百強企業在人工智能、物聯網等領域的投入強度同比提升40%&#xff0c;展現出強勁的技術引領力。與此同時&#xff0c…

linux多線(進)程編程——(4)進程間的傳音術(命名管道)

前言&#xff08;前情回顧&#xff09; 進程君&#xff08;父進程&#xff09;在開發出匿名管道這門傳音術后&#xff0c;解決了和自己孩子&#xff08;子進程&#xff09;間的溝通問題&#xff0c;父子關系趨于融洽。和孩子溝通后&#xff0c;進程君發現&#xff0c;自己脫離…

在IDEA里面建立maven項目(便于java web使用)

具體步驟&#xff1a; 第一次有的電腦你再創建項目的時候右下角會提醒你彈窗&#xff1a;讓你下載沒有的東西 一定要下載&#xff01;&#xff01;可能會很慢 運行結果&#xff1a; 因為他是默認的8080端口所以在運行的時候輸入的url如下圖&#xff1a; 新建了一個controller代…

【13】數據結構之樹結構篇章

目錄標題 樹Tree樹的定義樹的基本概念樹的存儲結構雙親表示法孩子表示法孩子兄弟表示法 二叉樹二叉樹與度不超過&#xff12;的普通樹的不同之處二叉樹的基本形態二叉樹的分類二叉樹的性質 二叉樹的順序存儲二叉樹的鏈式存儲二叉樹的鏈式存儲的結點結構樹的遍歷先序遍歷中序遍歷…

雷達生命探測儀,地震救援的生命探測先鋒|鼎躍安全

在地震、山體滑坡、坍塌建筑等突發災害中&#xff0c;會嚴重摧毀建筑物&#xff0c;造成倒塌和人員被困&#xff1b;在瓦礫堆、混凝土板層中&#xff0c;受困人員的生命安全常常面臨嚴峻威脅。傳統救援手段通常存在響應時間長、監測精度有限等不足。 救援現場往往環境復雜&…