代碼隨想錄算法訓練營第六天 - 哈希表2 || 454.四數相加II / 383.贖金信 / 15.三數之和 / 18.四數之和

代碼隨想錄算法訓練營第六天 - 哈希表2 || 454.四數相加II / 383.贖金信 / 15.三數之和 / 18.四數之和

  • 454.四數相加II
    • 解題思路
  • 383.贖金信
  • 自己解答:
    • 代碼隨想錄講解
      • 暴力做法
      • 哈希表
  • 15.三數之和
    • 雙指針
    • 優化改進
  • 18.四數之和
    • 自己的解答
    • 系統講解

454.四數相加II

文檔講解:代碼隨想錄算法訓練營
視頻講解:算法視頻公開課
狀態:思路自己想出來了,但代碼沒有實現出來

解題思路

首先如果使用暴力方法,也就是對數組nums1nums2依次遍歷,直到找到符合要求的組合,那么時間復雜度為O(n^4)
如何能減少時間復雜度呢?
想到之間 242.有效字母異位詞 的解法,我們可以遍歷nums1nums2,求出二者num1 + num2之和的組合,并記錄出現的次數。
接著,我們再遍歷nums3nums4,現在我們的目標值是找到target = 0 - num3 - num4,因為題目要求num1 + num2 + num3 + num4 = 0,也就是要找num1 + num2 = - (num3 + num4)。然后在map里找target是否出現過,如果出現過,計數的變量count要加上targetmap里的value值,即targetmap里存儲的次數。
代碼實現:

class Solution {
public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int,int> map;// 遍歷 nums1 和 nums2for (int num1 : nums1) {for (int num2 : nums2) {map[num1 + num2] ++;}}int count = 0;// 遍歷 nums3 和 nums4for (int num3 : nums3) {for (int num4 : nums4) {int target = 0 - num3 - num4;if (map.find(target) != map.end()) {count += map[target];}}}return count;}
};

383.贖金信

文檔講解:代碼隨想錄算法訓練營
狀態:自己完全做出來了

自己解答:

class Solution {
public:bool canConstruct(string ransomNote, string magazine) {unordered_map<int,int> map;// 遍歷 magazine 字符串for (int i = 0; i < magazine.size(); i++) {map[magazine[i] - 'a'] ++;}// 遍歷 ransomNote 字符串for (int i = 0; i < ransomNote.size(); i++) {map[ransomNote[i] - 'a'] --;}// 是否有 value < 0,如果有就不能構成for (int i = 0; i < 26; i++) {if (map[i] < 0) return false; }return true;}
};

代碼隨想錄講解

暴力做法

class Solution {
public:bool canConstruct(string ransomNote, string magazine) {// 遍歷 magazine 和 ransomNotefor (int i = 0; i < magazine.size(); i++) {for (int j = 0; j < ransomNote.size(); j++) {// 如果找到相同字符,就把這個字符從 ransomNote里刪除if (magazine[i] == ransomNote[j]) {ransomNote.erase(ransomNote.begin() + j);}}}// 如果 ransomNote 里還有字符,那么就不構成if (ransomNote.length() != 0) return false;return true;}
};

哈希表

題目說只有小寫字母,采用空間換取時間的哈希策略,用一個長度為26的數組來記錄magazine出現字母的次數。
為什么不采用map呢,因為map要維護紅黑樹或者哈希表,而且還要做哈希函數,是費時的!數據量大的話就能體現出來差別了。 所以數組更加簡單直接有效!

class Solution {
public:bool canConstruct(string ransomNote, string magazine) {int hash[26] = {};for (int i = 0; i < magazine.size(); i++) {hash[magazine[i] - 'a'] ++;}for (int i = 0; i < ransomNote.size(); i++) {hash[ransomNote[i] - 'a'] --;}for (int i = 0; i < 26; i++) {if (hash[i] < 0) return false;}return true;}
};

15.三數之和

文檔講解:代碼隨想錄算法訓練營
視頻講解:算法視頻公開課
狀態:自己有思路,在代碼隨想錄基礎上做優化

雙指針

這道題要使用哈希表的話,在去重操作中可能非常復雜,很難寫全。
這道題應該使用雙指針法
步驟一:先對數組進行從小到大排序;
步驟二:遍歷數組,注意我們只需要遍歷到數組的倒數第三個位置即可,因為我們需要 leftright,并且 i < left < right
步驟三:去重。如果第一個數大于0即 nums[i] > 0,那么直接返回即可,不可能再有答案了。如果循環中,這個元素和上一個元素數值相等,那么直接跳過。
注意:我的語言描述是,這個元素和上一個元素數值相等,不是這個元素和下一個元素數值相等。這是有區別的,比如nums = [-1, -1, 0, 1, 2],當 i = 0 的時候,此時指向第一個 -1,如果判斷這個元素與下一個元素,即 i = 1 的時候,此時指向的數也為 -1,那么就應該跳過 i = 0,明顯是不正確的。正確應該是==該元素與上一個元素的值相等,跳過該元素。
步驟三:設 left = i + 1, right = n - 1,開始循環,循環條件是left < right,注意這里不能加上=,當想到等時候就應該終止循環,而不是接著循環。
步驟四:當三數之和 > 0,那么讓 right --;如果三數之和 < 0,那么就讓 left ++;如果三數之和 = 0,就把結果放入到答案數組res中。
步驟五:放入res后,需要對leftright去重,如果 left < right,這個是前提,也必須在循環條件里,不寫的話,可能造成死循環,比如數組nums = [0, 0, 0, 0, 0],就會一直循環到頭。對于right,如果下一個元素和該元素相等,那么就跳過元素;對于left,如果下一個元素和該元素相等,就跳過元素。
步驟六:找到符合要求的一組時,要讓leftright收縮

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> res;int n = nums.size();// 對數組 nums 進行從小到大排序sort(nums.begin(), nums.end());for (int i = 0; i < n - 2; i ++) {if (nums[i] > 0) return res;if (i > 0 && nums[i] == nums[i - 1]) continue;int left = i + 1;int right = n - 1;while (left < right) {if (nums[i] + nums[left] + nums[right] > 0) right --;else if (nums[i] + nums[left] + nums[right] < 0) left ++;else {res.push_back({nums[i], nums[left], nums[right]});while (left < right && nums[left] == nums[left + 1]) left ++;while (left < right && nums[right] == nums[right - 1]) right --;// 找到解,收縮left 和 rightleft ++;right --;}}}return res;}
};

優化改進

可以加上幾個判斷:
如果nums的前三個元素之和 > 0,那么不可能再有解,直接break
如果nums的后兩個元素 + nums[i] < 0 ,那么可以跳過本次循環,leftright無論怎么移動也不能得到答案。
注意寫i + 1i + 2,for循環中一定寫的是i < n - 2,否則會造成越界訪問

			if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break;if (nums[i] + nums[n - 2] + nums[n - 1] < 0) continue;

除此之外,在找到答案的時候,對leftright的處理還可以再優化,代碼更簡潔,更易理解。
每次找到答案,我們先對leftright進行收縮操作,然后進行判重,也就是如果left < right,對于left,就是,該元素與上一個元素相等,就跳過,和步驟三一致。

		for (left ++; left < right && nums[left] == nums[left - 1]; left ++);for (right --; left < right && nums[right] == nums[right + 1]; right --);
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> res;int n = nums.size();sort(nums.begin(), nums.end());for (int i = 0; i < n - 2; i ++) {if (nums[i] > 0) return res;if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break;if (nums[i] + nums[n - 2] + nums[n - 1] < 0) continue;if (i > 0 && nums[i] == nums[i - 1]) continue;int l = i + 1, r = n - 1;while (l < r) {if (nums[i] + nums[l] + nums[r] > 0) r --;else if (nums[i] + nums[l] + nums[r] < 0) l ++;else {res.push_back({nums[i], nums[l], nums[r]});for (l ++; l < r && nums[l] == nums[l - 1]; l ++);for (r --; l < r && nums[r] == nums[r + 1]; r --);}}}return res;}
};

18.四數之和

文檔講解:代碼隨想錄算法訓練營
視頻講解:算法視頻公開課
狀態:自己仿照三數之和做出來了,調試了好幾次,int換成long long,剪枝的位置不正確等等,最后還是AC了

自己的解答

class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> res;sort (nums.begin(), nums.end());int n = nums.size();for (int i = 0; i < n - 3; i ++) {if (i > 0 && nums[i] == nums[i - 1]) continue;if ((long long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;if ((long long)nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) continue;for (int j = i + 1; j < n - 2; j ++) {if (j > i + 1 && nums[j] == nums[j - 1]) continue;int l = j + 1, r = n - 1;while (l < r) {if ((long long)nums[i] + nums[j] + nums[l] + nums[r] > target) r --;else if ((long long)nums[i] + nums[j] + nums[l] + nums[r] < target) l ++;else {res.push_back({nums[i], nums[j], nums[l], nums[r]});for (l ++; l < r && nums[l] == nums[l - 1]; l ++);for (r --; l < r && nums[r] == nums[r + 1]; r --);}} }}return res;}
};

系統講解

本題和三數之和非常像,整體思路就是在三數之和的循環外,再套上一層循環即可。
這里要注意剪枝和去重。
首先對于一級剪枝操作,這里不能直接寫nums[i] > target,直接就break 這是錯誤的,如果target < 0,num[i] < 0,負數加負數會變的越來越小,還是可能有解的,所以我們要加上條件。對于剪枝,同理還有如果前四個數之和 > target,直接break;nums[i]加上后三個數 < target,continue,注意,這里要轉成long long類型才能過。
對于去重,和之前同理。

	// 一級剪枝操作if (nums[i] > target && nums[i] > 0 && target > 0) break;if ((long long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;if ((long long)nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) continue;// 一級去重if (i > 0 && nums[i] == nums[i - 1]) continue;

二級去重,就仿照一級去重來寫,把nums[i] + nums[j]當成一個整體。

class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> res;int n = nums.size();sort(nums.begin(), nums.end());for (int i = 0; i < n - 3; i ++) {// 一級剪枝,注意 long longif (nums[i] > target && nums[i] > 0 && target > 0) break;if ((long long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;if ((long long)nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) continue;// 一級去重if (i > 0 && nums[i] == nums[i - 1]) continue;for (int j = i + 1; j < n - 2; j++) {// 二級剪枝if (nums[i] + nums[j] > target && nums[i] + nums[j] > 0 && target > 0) break;if ((long long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;if ((long long)nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) continue;// 二級去重if (j > i + 1 && nums[j] == nums[j - 1]) continue;// 下面同三數之和邏輯int l = j + 1, r = n - 1;while (l < r) {if ((long long)nums[i] + nums[j] + nums[l] + nums[r] > target) r --;else if ((long long)nums[i] + nums[j] + nums[l] + nums[r] < target) l ++;else {res.push_back({nums[i], nums[j], nums[l], nums[r]});for (l ++; l < r && nums[l] == nums[l - 1]; l ++);for (r --; l < r && nums[r] == nums[r + 1]; r --);}}}}return res;}
};

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

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

相關文章

FPGA實現流水式排序算法

該算法采用雙調排序算法&#xff0c;是一種可流水的遞推算法&#xff0c;且算法的消耗時長可算&#xff0c;具體細節參考視頻&#xff1a; https://www.bilibili.com/video/BV1S3thzWEnh/?spm_id_from333.1387.homepage.video_card.click&vd_source69fb997b62efa60ae1add…

平衡車 -- MPU6050

&#x1f308;個人主頁&#xff1a;羽晨同學 &#x1f4ab;個人格言:“成為自己未來的主人~” 傳感器原理 此外&#xff0c;用陀螺儀獲取x,y,z軸的加速度。 初始化 我們現在對MPU6050進行初始化&#xff0c;MPU6050通過I2C總線與單片機進行通信&#xff0c;通過的是PB8和PB…

在電路浪涌測試中,TVS(瞬態電壓抑制二極管)的防護效果確實會受到陪測設備中去耦網絡(Decoupling Network,DN)的顯著影響

在電路浪涌測試中&#xff0c;TVS&#xff08;瞬態電壓抑制二極管&#xff09;的防護效果確實會受到陪測設備中去耦網絡&#xff08;Decoupling Network&#xff0c;DN&#xff09;的顯著影響&#xff0c;這一現象與浪涌能量的傳遞路徑、阻抗匹配及信號完整性密切相關。結合 AD…

Redis之分布式鎖與緩存設計

1、分布式鎖 1.1、超賣問題/*** 存在庫存超賣的不安全問題*/private void deductStock() {int stockTotal Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stockTotal > 0) { // 這里存在多個線程、進程同時判斷通過&#xff0c;然后超買…

靜態住宅IP的特點

穩定性高&#xff1a;與動態IP地址相比&#xff0c;靜態住宅IP不會不定時變更&#xff0c;能確保業務在網絡環境中的一致性和連貫性&#xff0c;適合需要長期維持同一身份的場景&#xff0c;如跨境電商業務等3。安全性強&#xff1a;由于其住宅屬性&#xff0c;看起來更像是正常…

Linux 編譯 Android 版 QGroundControl 軟件并運行到手機上

Linux 編譯 Android 版 QGroundControl 軟件并運行到手機上環境說明操作步驟一、參考上一篇文章在電腦端把環境搭建好二、配置 Qt Creator 的 Android 環境環境說明 電腦系統 Ubuntu 22.04 qgroundcontrol master 分支 Qt 6.8.3 操作步驟 一、參考上一篇文章在電腦端把環境搭…

Python 2025:量化金融與智能交易的新紀元

當Python遇見金融大數據&#xff0c;算法交易正迎來前所未有的技術變革在2025年的技術浪潮中&#xff0c;Python已經從一個"膠水語言"蛻變為金融科技領域的核心驅動力。根據GitHub 2025年度報告&#xff0c;Python在量化金融項目中的使用率增長了217%&#xff0c;在對…

[論文閱讀] 人工智能 + 軟件工程 | TDD痛點破解:LLM自動生成測試骨架靠譜嗎?靜態分析+專家評審給出答案

TDD痛點破解&#xff1a;LLM自動生成測試骨架靠譜嗎&#xff1f;靜態分析專家評審給出答案 論文信息項目詳情論文原標題Evaluation of Large Language Models for Generating RSpec Test Skeletons in Ruby on Rails論文鏈接https://arxiv.org/pdf/2509.04644一段話總結 該研究…

開源PSS解析器1

本章介紹另一個開源PSS解析工具zuspec&#xff1a; zuspec 提供了一組用于處理 actions relationship level 的工具 &#xff08;ARL&#xff09; 模型&#xff0c;主要是使用 Accellera 便攜式測試和刺激 &#xff08;PSS&#xff09; 語言描述的模型。ARL 模型用于為數字設計…

26考研——內存管理_內存管理策略(3)

408答疑 文章目錄一、內存管理策略1、內存管理的基本原理和要求1.1、相關概念1.2、邏輯地址與物理地址1.3、程序的鏈接與裝入1.4、進程的內存映像1.5、內存保護1.6、內存共享1.7、內存分配與回收1.8、在存儲管理中涉及到兩個問題2、連續分配管理方式2.1、相關概念2.2、單一連續…

Python爬蟲實戰:研究Event Handling機制,構建在線教育平臺的課程數據采集和分析系統

1. 引言 1.1 研究背景與意義 在大數據時代,互聯網作為全球最大的信息載體,蘊含著海量有價值的數據。這些數據涵蓋了商業交易、用戶行為、社會趨勢等多個領域,對企業決策、學術研究和社會管理具有重要參考價值。如何高效、準確地獲取這些數據并進行深度分析,成為當前數據科…

docker 安裝 redis 并設置 volumes 并修改 修改密碼(四)

設置新密碼: 127.0.0.1:6379> CONFIG SET requirepass newpassword OK驗證新密碼: 127.0.0.1:6379> AUTH newpassword OK更新配置文件: 編輯主機的配置文件/data/redis/conf/redis.conf,將requirepass的值修改為新密碼: requirepass newpassword重啟容器以使配置…

NBA球星知識大挑戰:基于 PyQt5 的球星認識小游戲

NBA球星知識大挑戰&#xff1a;基于 PyQt5 的球星認識小游戲 代碼詳見&#xff1a;https://github.com/xiaozhou-alt/NBA_Players_Recognition 文章目錄 NBA球星知識大挑戰&#xff1a;基于 PyQt5 的球星認識小游戲一、項目介紹二、文件夾結構三、項目實現1. 自定義動畫按鈕&a…

電磁波成像(X射線、CT成像)原理簡介

電磁波成像&#xff08;X射線、CT成像&#xff09;原理簡介一、圖像形成的一般形式二、可見光成像2.1可見光2.2可見光成像三、其他電磁波成像3.1X射線成像3.2CT成像3.2.1CT成像原理3.2.2CT成像與X射線成像對比3.2.3CT生成三維描述3.3PET成像一、圖像形成的一般形式 大多數圖像…

k8s部署2:前置條件:docker部署

前兩天發布了k8s的前置發布條件,對于防火墻的處理,我看大家反響還不錯,所以作為先行者,我感覺自己多了不少動力,所以今天來說說k8s部署前置條件中docker部分的部署。在此先感謝一下那些點贊和添加收藏的朋友們,你們的支持是我永遠的動力!三克油喂給馬吃! 之前寫過docke…

某開源漫畫系統RCE代碼審計

免責聲明 本文檔所述漏洞詳情及復現方法僅限用于合法授權的安全研究和學術教育用途。任何個人或組織不得利用本文內容從事未經許可的滲透測試、網絡攻擊或其他違法行為。使用者應確保其行為符合相關法律法規&#xff0c;并取得目標系統的明確授權。 對于因不當使用本文信息而造…

Pandas DataFrame 指南

&#x1f4ca; Pandas DataFrame 常用操作代碼示例 下面用表格匯總了 DataFrame 的常用操作&#xff0c;方便你快速查閱和實踐。 操作類別代碼示例說明&#xff08;簡要&#xff09;數據讀取df pd.read_csv(data.csv)讀取 CSV 文件df pd.read_excel(data.xlsx, sheet_nameS…

React學習教程,從入門到精通, React 樣式語法知識點與案例詳解(13)

React 樣式語法知識點與案例詳解 作為React初學者&#xff0c;掌握樣式語法是構建美觀UI的關鍵。本文將詳細介紹React中所有主要的樣式方法&#xff0c;并提供詳細注釋的案例代碼。 一、React樣式語法知識點總覽 1. 行內樣式 (Inline Styles) 使用style屬性&#xff0c;值為Jav…

Proxychains 配置全解析:從入門到高級應用

引言 在數字時代&#xff0c;網絡隱私與安全至關重要。無論是繞過地理限制訪問內容&#xff0c;還是在滲透測試中隱藏蹤跡&#xff0c;代理工具都不可或缺。Proxychains&#xff08;或稱 Proxychains-NG&#xff09;作為一款經典的開源代理鏈工具&#xff0c;以其高效靈活的特性…

二叉樹的前中后序遍歷(迭代法)

目錄 題目鏈接&#xff1a; 題目&#xff1a; 解題思路&#xff1a; 代碼&#xff1a; 前序遍歷&#xff1a; 中序遍歷&#xff1a; 后序遍歷&#xff1a; 總結&#xff1a; 題目鏈接&#xff1a; 144. 二叉樹的前序遍歷 - 力扣&#xff08;LeetCode&#xff09; 94. …