暑期算法訓練.2

目錄

6.力扣 11.盛水最多的容器

6.1 題目解析:

6.2 算法思路:

6.2.1 暴力解法:

6.2.2 優化算法:

6.3 代碼演示:

?編輯

6.4 總結反思:

7.力扣 611.有效的三角形個數

7.1 題目解析:

?7.2 算法思路:

7.3 代碼演示:

?編輯

?7.4 總結反思:

8.力扣 LCR.179 查找總價格為目標值的兩個商品

8.1 題目解析:

8.2 算法思路:

8.2.1 暴力解法:

8.2.2 優化解法:

?編輯8.3 代碼演示:

?編輯

?8.4 總結反思:

9.力扣 15.三數之和

9.1題目解析:

9.2 算法思路:

9.3 代碼演示 :

9.3.1 正確代碼演示:

9.3.2 錯誤代碼演示:

9.4 總結反思:

10.力扣 18.四數之和

10.1 題目解析:

10.2 算法思路:

?10.3 代碼演示:

10.4 反思總結:


6.力扣 11.盛水最多的容器

6.1 題目解析:

其實這道題目呢,就是讓你在給定的數組內尋找到兩個數相乘的最大值(但這i兩個數字不是隨便的兩個數,由題意可得,這個“高”其實是遵循的是短板效應,即看的是短的那一邊。)

6.2 算法思路:

6.2.1 暴力解法:

其實,當咱們看到一道題目的時候,最先想到的應該就是暴力解法,這道題也有對應的暴力解法。就是一個一個的進行枚舉,相乘,然后選出最大的值即可。當然,容器的容積的計算:

1.首先得從height[i],height[j]中選出最小的值。

2.之后計算j-i的值,之后相乘即可。

那么咱們來看一下暴力解法的偽代碼:

for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)check(nums[i],nums[i])

但是這樣寫的話,一旦給的數組里面的元素特別多,就會超時,所以第一種方法不可取。

6.2.2 優化算法:

這種算法是根據暴力解法的枚舉改進而來。暴力解法為什么會超時?是因為它進行了太多的無意義的比較。?

就拿這個進行舉例子,暴力是不管三七二十一,直接全部進行相乘,然后比較。咱們其實可以帶一帶腦子,比如上圖,你讓j往左挪動,這個j-i是一直在減小的。而且,j往左挪動,由于挪動的邊始終比i小,所以高也是在不段減小的。所以這個時候,就不需要再進行比較了,因為從i到j之間,不可能有比(j-i)*j更大的。那么此時就不需要比較這一部分。

還有一點就是,咱們要移動就移動短邊,為什么呢?因為你越往內,這個長度越小,那么想找到比原來面積大的,只能靠高(找到比原來更高的高)。而咱們知道,這個受限于短板,所以高的大小得看短板,并且動短邊,高度變大的可能性更大。想一想,因為它是取決于短邊的。

所以,動的時候,先去比較左右板誰小,誰小誰就動,動完后再進行面積的計算,再比較這個面積與原面積,留下面積比較大的那一個。

6.3 代碼演示:

int main()
{vector<int> height = { 1,8,6,2,5,4,8,3,7 };int ret = 0;int left = 0;int right = height.size() - 1;while (left < right){int tmp = min(height[left], height[right]) * (right - left);ret = max(ret, tmp);//找出最大的之間也要進行比較,選出更大的if (height[right] > height[left]){left++;}else{right--;}}cout << ret << endl;return 0;
}

?代碼就是左右板,誰小就動誰。

6.4 總結反思:

對于很多的題來說,優化的算法都是在暴力的基礎上進行改良的。所以咱們一開始想不到優化的解法,不用慌張,先寫出來暴力解法,然后再仔細的分析。

7.力扣 611.有效的三角形個數

7.1 題目解析:

這道題的題意很好理解,就是給你一個數組,返回數組里面可以組成三角形的三元組的個數即可。

?7.2 算法思路:

相信大家都知道判斷三角形的條件是任意兩邊之和大于第三邊。但是呢,這個其實需要三個條件。但是呢,還有一種方法,只需要一個條件便可以判斷出是否為三角形。

前提是咱們得知道這三條邊的大小。

好,那么接下來講解一下這道題運用到的算法思路:

找單調,然后用雙指針解決這道問題:

1.首先得先排好序,因為要用那個結論,就得保證是升序的。

2.那么利用有序數組就是使用單調性。怎么個單調法呢?

3.首先固定住一個最大的數字。

4.在最大的數字的左邊的區間內,使用雙指針法計算出符合要求的三元組的個數。

很明顯,得有兩層循環才能完成吧。

?

假設此時a+b>c,那么從a往右一直到b這個區間內,都是比a大的,那么這個區間內的再加上b是不是也是一定大于c的?好,那么這個時候,你要是挪動a就沒有任何意義了。這個時候,只需要往左挪動b即可。

?

此時的a+b<c,好,那么此時,從b往左一直到a的位置,這個區間內的值都是小于b的,所以a加上這個區間內的任意一個值,肯定也都是小于c的。所以此時挪動b無意義,需要將a往左挪動。

............以此類型。直到left>=right為止。

這才是完成了一個小循環,之后在移動c,再進行下一個小循環。

所以?

那么到現在為止,代碼相信大家都可以自己寫出來了吧。

7.3 代碼演示:

int main()
{vector<int> nums = { 2,2,3,4 };//1.先進行排序sort(nums.begin(), nums.end());//2.進行計算個數int ret = 0;int n = nums.size();for (int i = n - 1; i >= 2; i--){int left = 0;int right = i - 1;while (left < right){if (nums[left] + nums[right] > nums[i]){ret += right - left;right--;}else{left++;}}}cout << ret << endl;return 0;
}

這是一個三元數組,所以c得到下標為2的位置停下。以及left與right必須得寫在for里面,因為left,right隨著c的變化為發生位置變化。?

?7.4 總結反思:

其實這道題也就是帶我們認識到了單調性+雙指針對于這類型題目的解法,為下面三道題打下了基礎。

8.力扣 LCR.179 查找總價格為目標值的兩個商品

8.1 題目解析:

題目很簡單,就是給定一個數組,再給定一個值,讓你在數組中尋找兩個元素和為目標值的二元數組,并且不管元素順序,返回一種叫即可。

8.2 算法思路:

8.2.1 暴力解法:

這道題搭眼一看,就知道肯定有暴力解法,就是寫兩層for循環,然后再將元素想加,看看哪兩個元素相加等于目標值,再返回這兩個元素組成的二元數組。但是這種解法容易超時,所以咱們重點來講解第二種優化算法。

8.2.2 優化解法:

其實這個題的解法與上一題的解法基本一致,咱們來看圖理解:

8.3 代碼演示:

vector<int> Judgment(vector<int>& price, int target)
{int left = 0;int right = price.size() - 1;while (left < right){if (price[left] + price[right] > target){right--;}else if (price[left] + price[right] < target){left++;}else return { price[left],price[right] };//多參數隱式類型轉換}return{ -1,-1 };//確保每個路徑下都有返回值
}

?8.4 總結反思:

這道題與上一道題的解法基本一致。

9.力扣 15.三數之和

9.1題目解析:

題目也挺好理解的,就是i,j,k三個元素相加為0,并且這三個元素不可以是同一個位置的,并且返回的時候,三元數組中的元素相同的,只能返回一組,這個意味著咱們是不是要進行去重呀。那去重的話,咱們肯定可以想到C++里面的unordered_set,使用容器去重。當然可以,但是,有沒有不使用容器就可以進行去重的呢?有!方法,咱們算法思路里面講解。

9.2 算法思路:

其實 ,這道題,你只要做過前面的那個題,這個題的算法思路就很容易想到。

好,這個題基本的核心的思路我已經全部羅列出來了,大家可以看一下。但這個地方,本博主寫代碼的時候,還是被弄暈了。

9.3 代碼演示 :

9.3.1 正確代碼演示:

vector<vector<int>> threeSum(vector<int>& nums)
{sort(nums.begin(), nums.end());vector<vector<int>> ret;int n = nums.size();int i = 0;while (i < n){int left = i + 1; int right = n - 1;while (left < right){if (nums[left] + nums[right] == -nums[i]){vector<int> frontret = { nums[left],nums[right],nums[i] };ret.push_back(frontret);left++, right--;// 去重操作left和right,先++left,--right,再去重//先去重,再移動left與right的方法不可取while (left < right && nums[left] == nums[left - 1]) left++;while (left < right && nums[right] == nums[right + 1])right--;}else if (nums[left] + nums[right] > -nums[i]){right--;}else {left++;}}i++;//外層i去重while (i < n && nums[i] == nums[i - 1]) i++;}return ret;
}
int main()
{vector<int> nums = { 2,-3,0,-2,-5,-5,-4,1,2,-2,2,0,2,-4,5,5,-10 };vector<vector<int>> kk = threeSum(nums);for (auto& e : kk){for (auto& m : e){cout << m << "";}cout << endl;}cout << endl;
}

這個地方的去重操作呢,必須得是先進行left,right的移動,之后再判斷這個位置與前一個位置的數字是否相等,如果相等,再加加,挪到要改變的那個元素的位置上。這是正確的邏輯。但是博主呢,正好邏輯相反,結果就這一個題在那里調試了一下午。

9.3.2 錯誤代碼演示:

去重邏輯混亂,不可取
vector<vector<int>> threeSum(vector<int>& nums)
{sort(nums.begin(), nums.end());vector<vector<int>> ret;int n = nums.size();int i = 0;while (i < n){int cout_i = 0;int left = i + 1; int right = n - 1;while (left < right){int cout_left = 0;int cout_right = 0;if (nums[left] + nums[right] == -nums[i]){vector<int> frontret = { nums[left],nums[right],nums[i] };ret.push_back(frontret);while ((left + 1 < n - 1) && (nums[left] == nums[left + 1])){if (left < n - 1){left += 1;cout_left++;}}while ((right - 1 > i + 1) && (nums[right] == nums[right - 1])){if (right > i + 1){right -= 1;cout_right++;}}if ((left < n - 2) && (cout_left == 0)){left++;}if ((right > i + 2) && (cout_right == 0)){right--;}}else if (nums[left] + nums[right] > -nums[i]){right--;}else {left++;}}while ((i + 1 < n - 2) && (nums[i] == nums[i + 1])  ){if (i < n - 2){i += 2;cout_i++;}}if (cout_i == 0){i++;}}return ret;
}
int main()
{vector<int> nums = { 2,-3,0,-2,-5,-5,-4,1,2,-2,2,0,2,-4,5,5,-10 };vector<vector<int>> kk = threeSum(nums);for (auto& e : kk){for (auto& m : e){cout << m << "";}cout << endl;}cout << endl;
}

這是我寫的代碼,我的本意是想著既然都去重了,那就先去重,如果重復了,那就加到不重復為止,且這種最后不需要再單獨加加了。之后再單獨加。但是呢,不對?。

1. **去重指針移動不正確**:在找到一組解后,對`left`和`right`的去重沒有正確地將指針移動到下一個不同元素的位置。例如,如果`left`位置有重復,它只是移動到了重復序列的最后一個,然后停止,這樣下一次循環還是相同的值(因為下一次循環時,`left`指向的還是重復序列的最后一個,而下一個元素就是不同的,但此時`left`并沒有指向下一個不同元素,所以循環會繼續使用這個重復序列的最后一個元素,導致重復解)。

2. **去重后指針移動邏輯混亂**:通過`cout_left`和`cout_right`來決定是否再移動一次,這種邏輯沒有道理。而且,在去重循環中,它只移動了重復元素,但并沒有確保移動后的指針指向的是一個新的值(即跳過重復后應該指向下一個不同的值)。

3. **固定數`i`的去重邏輯錯誤**:使用`i+=2`來跳過重復,這會導致當重復次數為奇數時,最后一個重復值仍然會被處理,造成重復解。而且,當重復次數超過2次時,跳躍步長固定為2,顯然不夠。

只能說,我還是個新手吧哈哈哈哈,做題做的還是少。

9.4 總結反思:

這道題想要真正的自己用代碼實現出來,真的挺不容易的。還是要多練習題目。

10.力扣 18.四數之和

10.1 題目解析:

你仔細的讀一讀這道題,會發現,這道題的解法與前面那個三數之和的解法基本一致。無非就是外面多套了層循環,多加了一個去重。

10.2 算法思路:

若還是不能夠理解,那么我畫一張圖就可以了:

1.依次固定一個數a

2.在a后面的區間內,利用“三數之和”找到三個數,使這三個數的和等于target-a即可

? ? ? ? 2.1 依次固定一個數b

? ? ? ? 2.2 在b后面的區間內,利用“雙指針”找到兩個數,使得兩個數的和為target-a-b即可

最后別忘了去重細節,有三個,left與right,b,a

以及還有越界的情況。最后考慮清楚,會發現與三數之和的代碼差不多一樣的。?

?10.3 代碼演示:

//四數之和思想與三數之和基本一致,連去重方法都是一樣的
vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;sort(nums.begin(), nums.end());int n = nums.size();for (int i = 0; i < n;) {for (int j = i + 1; j < n;) {int left = j + 1;int right = n - 1;long long aim = (long long)target - nums[i] - nums[j];while (left < right) {if (nums[left] + nums[right] ==aim) {vector<int> frontret = { nums[left], nums[right],nums[i], nums[j] };ret.push_back(frontret);++left;--right;// 只有這樣寫才能確保最后一個位置的元素是在不重復的那個位置底下while (left < right && nums[left] == nums[left - 1]) {left++;}while (left < right && nums[right] == nums[right + 1]) {right--;}}else if (nums[left] + nums[right] >aim) {right--;}else {left++;}}j++;while (j < n && nums[j] == nums[j - 1]) {j++;}}i++;while (i < n && nums[i] == nums[i - 1]) {i++;}}return ret;
}

?三個去重以及邊界判定別忘了。

10.4 反思總結:

題目之間都是相互連接的,咱們只有真正弄懂了一道題目,理解其中的解法,再遇到下一個題目的時候,才有應對之策,才能臨陣不慌。

...............本篇完

?

?

?

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

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

相關文章

華為OD 消消樂游戲

1. 題意 游戲規則&#xff1a;輸入一個只包含英文字母的字符串&#xff0c;字符串中的兩個字母如果相鄰且相同&#xff0c;就可以消除。 在字符串上反復執行消除的動作&#xff0c;直到無法繼續消除為止&#xff0c;此時游戲結束。 輸出最終得到的字符串長度。 輸入 輸入原始…

小白學HTML,操作HTML文件篇(2)

目錄 一、添加多媒體 1.添加網頁圖片 2.添加網頁音頻 3.添加網頁視頻 二、創建容器 1. 標簽 2.布局 三、創建表格 1.表格標簽 2.添加表格表頭 3.添加表格標題 一、添加多媒體 在 HTML 網頁中可以輕松地使用標簽來添加圖片、音頻、視頻等多媒體&#xff0c;而這些多媒體并…

微服務架構中實現跨服務的字段級權限統一控制

結合集中式權限管理、分布式上下文傳遞、動態策略執行等技術 ??一、核心架構設計?? ??1. 分層控制模型?? ??網關層??:統一校驗用戶身份與基礎權限,攔截非法請求。 ??服務層??:基于用戶權限動態過濾數據字段,實現業務級控制。 ??策略中心??:集中管理權…

【實現100個unity特效之27】使用unity的ShaderGraph實現一個帶裁剪邊緣光的裁剪效果(2d3d通用)

文章目錄普通裁剪效果1、創建一個Lit Shader Graph2、ShaderGraph前置配置3、添加節點4、效果5、修改裁剪方向帶邊緣色的裁剪1、在裁剪的基礎上添加裁剪邊緣光2、邊緣的亮度3、修改裁剪方向4、效果5、我們可以代碼控制它的變化&#xff0c;如下2D3D游戲通用專欄推薦完結普通裁剪…

Android Scoped Storage適配完全指南

Android Scoped Storage適配完全指南關鍵詞&#xff1a;Android、Scoped Storage、適配、存儲權限、文件訪問摘要&#xff1a;本文將全面介紹Android Scoped Storage的相關知識&#xff0c;從背景出發&#xff0c;詳細解釋核心概念&#xff0c;闡述其原理和架構&#xff0c;給出…

Typecho集成PHPMailer實現郵件訂閱功能完整指南

文章目錄 Typecho使用PHPMailer實現文章推送訂閱功能詳解 1. 背景與需求分析 1.1 為什么選擇PHPMailer 1.2 功能需求 2. 環境準備與配置 2.1 安裝PHPMailer 2.2 數據庫設計 3. 核心功能實現 3.1 郵件服務封裝類 3.2 訂閱功能實現 3.2.1 訂閱表單處理 3.2.2 確認訂閱處理 3.3 文…

無線-二層組網-直接轉發

文章目錄無線二層組網直接轉發&#x1f3e1;作者主頁&#xff1a;點擊&#xff01; &#x1f916;Datacom專欄&#xff1a;點擊&#xff01; ??創作時間&#xff1a;2025年07月16日08點00分 無線二層組網 直接轉發 本地轉發中所有的沿途都需要配置對應VLAN的通過&#xff…

gin go-kratos go-zero框架對比

Gin、Go-Kratos 和 Go-Zero 是 Go 語言中三種常見的服務框架&#xff0c;它們在定位、設計理念、復雜度和適用場景上差異較大。下面我們從功能定位、設計理念、優劣對比、使用建議等維度進行深入對比。&#x1f9ed; 一句話總結框架定位Gin輕量級、高性能的 HTTP 路由框架Go-Kr…

4G模塊 A7670發送英文短信到手機

命令說明ATi顯示產品的標志信息 ATCIMI查詢IMSI ATCICCID從SIM卡讀取ICCID ATCGSN查詢產品序列號 ATCPIN查詢卡狀態 ATCSQ查詢信號強度 ATCGATT查詢當前PS域狀態 ATCREG查詢GPRS注冊狀態 ATCEREG查詢4G注冊狀態 ATCGPADDR查詢PDP地址 ATCMGF選擇短信格式 ATCMGS發送短信流程第一…

歸并排序遞歸法和非遞歸法的簡單簡單介紹

基本思想&#xff1a; 歸并排序&#xff08;MERGE-SORT&#xff09;是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一個非常典型的應用。將已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每個…

webrtc之子帶分割下——SplittingFilter源碼分析

文章目錄前言一、頻帶分割過程1.SplittingFilter的創建2.頻帶分割整體流程1&#xff09;分割時機2&#xff09;分割規則3&#xff09;分割核心代碼3.頻帶合并二、算法實現1.實現原理介紹2.All pass QMF系統源碼1&#xff09;提高精度2&#xff09;經過串聯全通濾波器3&#xff…

Java運維之Tomcat升級

Tomcat升級準備工作 下述所有過程中,包含了兩種升級方式,一種是備份舊版本的 bin 和 lib,將新版本的 bin 和 lib 對舊版本進行覆蓋;另一種是直接備份舊版本的Tomcat包,運行新版本,將舊版本的配置文件(conf/ * )和應用(webapps/ * )等同步到新版本。 1. 到官網下載指…

MySQL的可重復讀隔離級別實現原理分析

MySQL 的 可重復讀&#xff08;Repeatable Read, RR&#xff09; 隔離級別主要通過 多版本并發控制&#xff08;Multi-Version Concurrency Control, MVCC&#xff09; 和 鎖機制&#xff08;特別是間隙鎖&#xff09; 來實現的。其核心目標是&#xff1a;在一個事務內&#xf…

利用Java自定義格式,循環導出數據、圖片到excel

利用Java自定義格式&#xff0c;循環導出數據、圖片到excel1、自定義格式循環導出數據1.1.設置格式1.1.1、居中樣式1.1.2、應用樣式到合并區域1.1.3、合并單元格1.1.4、設置列寬1.2、寫入數據1.2.1、創建標簽頭部1.2.2、寫入標簽內容2、自定義格式循環導出圖片2.1、設置格式并插…

SAP學習筆記 - 開發45 - RAP開發 Managed App New Service Definition,Metadata Extension

上一章講了在 Data Model View ( CDS View for BO Structure )基礎上創建 Projection View ( CDS View for BO Projection )。 SAP學習筆記 - 開發44 - RAP開發 Managed App 建 Projection View&#xff0c;Provider Contract&#xff0c;用 redirected to 設定父子關系-CSDN博…

React強大且靈活hooks庫——ahooks入門實踐之高級類hook(advanced)詳解

什么是 ahooks&#xff1f; ahooks 是一個 React Hooks 庫&#xff0c;提供了大量實用的自定義 hooks&#xff0c;幫助開發者更高效地構建 React 應用。其中高級類 hooks 是 ahooks 的一個重要分類&#xff0c;專門用于處理一些高級場景&#xff0c;如受控值、事件發射器、性能…

計算機網絡——數據鏈路層(25王道最新版)

數據鏈路層前言數據鏈路層的功能封裝成幀&#xff08;組幀&#xff09;字符計數法字節填充法零比特填充法違規編碼法小節差錯控制檢錯編碼奇偶校驗碼CRC校驗碼&#xff08;循環冗余校驗碼&#xff09;基本思想如何構造如何檢錯糾錯糾錯編碼海明校驗碼設計思路求解步驟&#xff…

【PTA數據結構 | C語言版】字符串替換算法

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 請編寫程序&#xff0c;將給定主串 s 中的子串 sub_s 替換成另一個給定字符串 t&#xff0c;再輸出替換后的主串 s。 輸入格式&#xff1a; 輸入給出 3 個非空字符串&#xff0c;依次為&#xff1a…

事物生效,訂單類內部更新訂單

代碼如下以下代碼1不生效&#xff0c;2生效解決方案1&#xff0c;外層方法加注解&#xff0c;內層不加2&#xff0c;不要拆分方法&#xff0c;把更新訂單操作放在帶事物的大方法中3&#xff0c;拆方法&#xff08;內部&#xff09;&#xff0c;注入自己&#xff0c;用代理對象調…

非對稱加密:RSA

文章目錄 非對稱加密:RSA 1、RSA 加解密 2、RSA 生成密鑰對(公鑰、私鑰)、加解密 參考資料 非對稱加密:RSA 1、RSA 加解密 <!-- RSA --><!-- 引入jsencrypt庫 --><script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js&q…