【算法訓練營Day06】哈希表part2

文章目錄

  • 四數相加
  • 贖金信
  • 三數之和
  • 四數之和

四數相加

題目鏈接:454. 四數相加 II

這個題注意它只需要給出次數,而不是元組。所以我們可以分治。將前兩個數組的加和情況使用map存儲起來,再將后兩個數組的加和情況使用map存儲起來,key存和,value存出現的次數。得到兩個map之后,我們遍歷其中一個map, 看另一個map中是否有和為0的情況,有就相加value,最后接可以得出答案。

在這種思路的基礎上,我們可以繼續優化代碼,例如我們在統計后兩個數組的同時,就已經可以將需要的和在前兩個數組的map中找出來,然后把次數進行相加。

代碼如下:

class Solution {public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {Map<Integer,Integer> records = new HashMap<>();for(int i = 0;i < nums1.length;i++) {for(int j = 0;j < nums2.length;j++) {records.put(nums1[i] + nums2[j],records.getOrDefault(nums1[i] + nums2[j],0) + 1);}}int result = 0;for(int i = 0;i < nums3.length;i++) {for(int j = 0;j < nums4.length;j++) {Integer count = records.get(0 - nums3[i] - nums4[j]);if(count != null) result += count;}}return result;}
}

贖金信

題目鏈接:383. 贖金信

二十六個字母,計數,第一反應就要想到數組。解題思路如下:

  • 用數組統計第一個單詞的個數
  • 然后遍歷第二個單詞,在數組中相應位置進行減法運算
  • 遍歷數組
    • 如果存在大于0的數返回false
    • 不存在則返回true
class Solution {public boolean canConstruct(String ransomNote, String magazine) {int[] records = new int[26];for (int i = 0; i < ransomNote.length(); i++) records[ransomNote.charAt(i) - 'a']++;for (int i = 0; i < magazine.length(); i++) records[magazine.charAt(i) - 'a']--;for (int i = 0; i < records.length; i++) if(records[i] > 0 ) return false;return true;}
}

三數之和

題目鏈接:15. 三數之和

解題思路:

看到這一題我們肯定會不自覺地拿它和兩數之和進行比較,我們是否能借助兩數之和的思想來完成這一題?首先我們回顧一下兩數之和的思想。在兩數之和中,我們是遍歷數組,每遍歷一個元素,就看target - 該元素 是否已經出現過(也就是是否在hash表中),如果在直接返回,如果不在就把這個元素添加到hash表中,代表該元素出現過,為后面的元素服務。

在三數相加中,我們嘗試沿用這種思路(先不直接到位,后面還會添加新邏輯):

  • 使用雙層for循環遍歷數組,外層循環相當于固定一個數,內層for循環沿用兩數相加的邏輯
  • 初始化一個hashset,用來存已經存在的數,外層循環的以固定值不需要存
  • 內存循環遍歷數組,尋找0 - nums[head]- nums[end] 是否存在于hashset中
  • 如果存在那么該數組添加到答案列表中
  • 如果不存在繼續遍歷
  • 外層循環每完成一次清空set
  • 最后返回答案集合

代碼如下:

class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();HashSet<Integer> set = new HashSet<>();for (int i = 0; i < nums.length; i++) {for (int j = i + 1; j < nums.length; j++) {int need = -nums[i] - nums[j];if (set.contains(need)) {result.add(Arrays.asList(nums[i], nums[j], need));} else {set.add(nums[j]);}}set.clear();}return result;}
}

這個代碼完成了基本的功能但是還差本題的一個重點那就是去重。

就比如題目的這個用例:[-1,0,1,2,-1,-4]
如下兩種情況就會重復:

  • i指向-1,j指向1,set里有0,這組會返回
  • i指向0,j指向-1,set里有1,這組也會返回

我們可以嘗試排序解決這個問題:

排序之后還是這個用例就變為:[-4,-1,-1,0,1,2]

外層循環在固定到兩個-1的時候肯定會發生重復,所以我們可以添加一個條件,外層循環固定的數字和上一次相同時直接跳過:

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();HashSet<Integer> set = new HashSet<>();for (int i = 0; i < nums.length; i++) {if (i > 0 && nums[i] == nums[i - 1]) {continue;}for (int j = i + 1; j < nums.length; j++) {int need = -nums[i] - nums[j];if (set.contains(need)) {result.add(Arrays.asList(nums[i], nums[j], need));} else {set.add(nums[j]);}}set.clear();}return result;}
}

改完之后發現這個測試用例過不了:
在這里插入圖片描述

原因就是當內層的兩數相加滿足之后,內層的下一次循環還是相同的數,那么相當于把這一組答案又加了一遍,那么我們針對這個情況進行改進:

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();HashSet<Integer> set = new HashSet<>();for (int i = 0; i < nums.length; i++) {if (i > 0 && nums[i] == nums[i - 1]) {continue;}Integer flag = null;for (int j = i + 1; j < nums.length; j++) {if(Integer.valueOf(nums[j]).equals(flag)) continue;flag = null;int need = -nums[i] - nums[j];if (set.contains(need)) {result.add(Arrays.asList(nums[i], nums[j], need));flag = nums[j];} else {set.add(nums[j]);}}set.clear();}return result;}
}

我們最后總結一下這道題:
這道題在沿用了我們前面兩數之和的思想之后,會存在一個去重問題:

  • 外層重復:也就是當外層循環固定的數字和上一次相同時此次循環直接跳過
  • 內層重復:也就是當內層的兩數相加滿足之后,內層的下一次循環還是相同的數。這個時候我們可以在每次三數之和滿足條件之后,將內層此次的值記錄一下,相鄰的下一次循環與此次的值一樣就跳過此次內循環。

當然此題也可以使用雙指針法來做,邏輯上更為簡單,代碼在此處不多做贅述。

四數之和

題目鏈接:18. 四數之和

這題使用雙指針法進行解題:

  • 將數組進行排序
  • 首先使用兩層的嵌套循環,固定兩個數
  • 然后再使用雙指針left、right確定最后兩個數
  • 將四個數字相加
    • 如果大于目標,right指針左移
    • 如果小于目標,left指針右移
    • 如果達到目標,left指針右移,right指針左移
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();for(int i = 0;i < nums.length;i++) {for(int j = i + 1;j < nums.length;j++) {int left = j + 1;int right = nums.length - 1;while(left < right && left < nums.length) {int sum = nums[i] + nums[j] + nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else {result.add(Arrays.asList(nums[i], nums[j], nums[left++],nums[right--]));}}}}return result;}
}

接下來進行去重:

在這里插入圖片描述

發生這種情況就是因為外層的雙層循環固定的兩個數字重復,我們添加去重的代碼:

class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();for(int i = 0;i < nums.length;i++) {if (i > 0 && nums[i] == nums[i - 1]) continue;for(int j = i + 1;j < nums.length;j++) {if (j > i + 1 && nums[j] == nums[j - 1]) continue;int left = j + 1;int right = nums.length - 1;while(left < right && left < nums.length) {int sum = nums[i] + nums[j] + nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else {result.add(Arrays.asList(nums[i], nums[j], nums[left++],nums[right--]));}}}}return result;}
}

這個去重的邏輯就是:

  • if (i > 0 && nums[i] == nums[i - 1]) continue; 因為數組是按大小排序的,如果第一個固定的數不變,那么其他三個數不管怎么樣,都只會與target相等(這個情況已經存在需要去重)或者比target大,所以這個循環可以直接跳過
  • if (j > i + 1 && nums[j] == nums[j - 1]) continue;邏輯類似

執行之后有一個測試樣例還是沒過:
在這里插入圖片描述
造成這個情況的原因是因為,左右指針同時內縮的時候如果元素不變也會發生重復,我們繼續往里面添加去重邏輯:

class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();for(int i = 0;i < nums.length;i++) {if (i > 0 && nums[i] == nums[i - 1]) continue;for(int j = i + 1;j < nums.length;j++) {if (j > i + 1 && nums[j] == nums[j - 1]) continue;int left = j + 1;int right = nums.length - 1;while(left < right && left < nums.length) {long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else {result.add(Arrays.asList(nums[i], nums[j], nums[left],nums[right]));while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;left++;right--;}}}}return result;}
}

注意:測試用例中有一個例子考察的是四數相加的范圍超出了int的最大表達值,所以四數相加的和sum要使用long來存儲在這里插入圖片描述

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

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

相關文章

JS手寫代碼篇---手寫apply方法

11、手寫apply方法 apply方法的作用&#xff1a; apply 是一個函數的方法&#xff0c;它允許你調用一個函數&#xff0c;同時將函數的 this 值設置為指定的值&#xff0c;并將函數的參數作為數組&#xff08;或類數組對象&#xff09;傳遞給該函數。 與call的區別&#xff1…

冪等性:保障系統穩定的關鍵設計

冪等性&#xff08;Idempotence&#xff09; 是計算機科學和分布式系統中的核心概念&#xff0c;指同一操作重復執行多次所產生的效果與執行一次的效果相同。這一特性對系統容錯性、數據一致性至關重要&#xff0c;尤其在網絡通信&#xff08;如HTTP&#xff09;和數據庫設計中…

electron定時任務,打印內存占用情況

// 監聽更新 function winUpdate(){// 每次執行完后重新設置定時器try {// 獲取當前時間并格式化為易讀的字符串const now new Date();const timeString now.toLocaleString();console.log(當前時間: ${timeString});// 記錄內存使用情況&#xff08;可選&#xff09;const m…

華為手機開機卡在Huawei界面不動怎么辦?

遇到華為手機卡在啟動界面&#xff08;如HUAWEI Logo界面&#xff09;的情況&#xff0c;可依次嘗試以下解決方案&#xff0c;按操作復雜度和風險由低到高排序&#xff1a; &#x1f527; 一、強制重啟&#xff08;優先嘗試&#xff09; 1.通用方法? 長按 ?電源鍵 音量下鍵?…

Python爬蟲之數據提取

本章節主要會去學習在爬蟲中的如何去解析數據的方法&#xff0c;要學習的內容有&#xff1a; 響應數據的分類結構化數據如何提取非結構化數據如何提取正則表達式的語法以及使用jsonpath解析嵌套層次比較復雜的json數據XPath語法在Python代碼中借助lxml模塊使用XPath語法提取非…

并行智算MaaS云平臺:打造你的專屬AI助手,開啟智能生活新紀元

目錄 引言&#xff1a;AI助手&#xff0c;未來生活的必備伙伴 并行智算云&#xff1a;大模型API的卓越平臺 實戰指南&#xff1a;調用并行智算云API打造個人AI助手 3.1 準備工作 3.2 API調用示例 3.3 本地智能AI系統搭建 3.4 高級功能實現 并行智算云的優勢 4.1 性能卓越…

三維坐標轉換

如果坐標(x,y,z)->(y,-z,-x)可以使用坐標系&#xff1a; import mathdef mat_vec_mult(matrix, vector):"""將 3x3 矩陣與 3x1 向量相乘。參數&#xff1a;matrix: 3x3 的旋轉矩陣vector: 3x1 的向量返回&#xff1a;3x1 的結果向量"""resul…

【C++高級主題】虛繼承

目錄 一、菱形繼承&#xff1a;虛繼承的 “導火索” 1.1 菱形繼承的結構與問題 1.2 菱形繼承的核心矛盾&#xff1a;多份基類實例 1.3 菱形繼承的具體問題&#xff1a;二義性與數據冗余 二、虛繼承的語法與核心目標 2.1 虛繼承的聲明方式 2.2 虛繼承的核心目標 三、虛繼…

什么是分布式鎖?幾種分布式鎖分別是怎么實現的?

一&#xff1a;分布式鎖實現思路 1.1 基本原理與實現方式 &#xff08;1&#xff09;分布式鎖的實現方式 &#xff08;2&#xff09;基于Redis的分布式鎖 獲取鎖 長時間無人操作&#xff0c;使鎖自動過期 添加鎖與設置過期時間需原子性 釋放鎖 1.2 實例 &#xff08;1&…

Legal Query RAG(LQ-RAG):一種新的RAG框架用以減少RAG在法律領域的幻覺

人工智能正在迅速改變法律專業人士的工作方式——從起草合同到進行研究。但盡管大型語言模型&#xff08;LLM&#xff09;功能強大&#xff0c;它們在關鍵領域卻常常出錯&#xff1a;真實性。當人工智能在法律文件中“幻覺”出事實時&#xff0c;后果可能是嚴重的——問問那些無…

如何用AI高效運營1000+Tiktok矩陣賬號

在當今數字化的時代&#xff0c;Tiktok 矩陣賬號運營成為了眾多企業和個人追求流量與變現的重要手段。然而&#xff0c;面對眾多的賬號管理&#xff0c;如何高效運營成為了關鍵。此時&#xff0c;AI 工具的出現為我們提供了強有力的支持。 一、Tiktok 矩陣賬號的重要性 Tiktok…

數據結構與算法學習筆記(Acwing 提高課)----動態規劃·樹形DP

數據結構與算法學習筆記----動態規劃樹形DP author: 明月清了個風 first publish time: 2025.6.4 ps??樹形動態規劃&#xff08;樹形DP&#xff09;是處理樹結構問題的一種動態規劃方法&#xff0c;特征也很明顯&#xff0c;會有一個樹形結構&#xff0c;其實是DFS的優化。…

得物GO面試題及參考答案

動態規劃的概念是什么&#xff1f; 動態規劃&#xff08;Dynamic Programming, DP&#xff09;是一種通過將復雜問題分解為重疊子問題&#xff0c;并利用子問題的解來高效解決原問題的方法。其核心思想在于避免重復計算&#xff0c;通過存儲子問題的解&#xff08;通常使用表格…

掃地機產品--氣壓傳感器器件異常分析

掃地機產品–氣壓傳感器器件異常分析 文章目錄 掃地機產品--氣壓傳感器器件異常分析一.背景1?.1 **標準大氣壓的定義與數值**?二.分析故障2.1**萬用表如何測量二極管**2.2 不良氣壓傳感器的萬用表二極管擋位測量結果分析。2.3 不良氣壓傳感器的開蓋分析2.4 結論2.5 后續措施三…

C#基礎語法(2)

### 練習 一、變量和數據類型 - 1. 變量定義與賦值 cs using System; namespace Name { class Program { public static void Main(string[] args) { int age 20; double height 1.75; string name "張三…

連接關鍵點:使用 ES|QL 聯接實現更豐富的可觀測性洞察

作者&#xff1a;來自 Elastic Luca Wintergerst ES|QL 的 LOOKUP JOIN 現已進入技術預覽階段&#xff0c;它允許你在查詢時對日志、指標和追蹤進行豐富處理&#xff0c;無需在攝取時進行非規范化。動態添加部署、基礎設施或業務上下文&#xff0c;減少存儲占用&#xff0c;加速…

Unity 中實現可翻頁的 PageView

之前已經實現過&#xff1a; Unity 中實現可復用的 ListView-CSDN博客文章瀏覽閱讀5.6k次&#xff0c;點贊2次&#xff0c;收藏27次。源碼已放入我的 github&#xff0c;地址&#xff1a;Unity-ListView前言實現一個列表組件&#xff0c;表現方面最核心的部分就是重寫布局&…

[Java 基礎]創建人類這個類小練習

請根據如下的描述完成一個小練習&#xff1a; 定義一個名為 Human 的 Java 類在該類中定義至少三個描述人類特征的實例變量&#xff08;例如&#xff1a;姓名、年齡、身高&#xff09;為 Human 類定義一個構造方法&#xff0c;該構造方法能夠接收所有實例變量作為參數&#xf…

LeetCode 熱題 100 739. 每日溫度

LeetCode 熱題 100 | 739. 每日溫度 大家好&#xff0c;今天我們來解決一道經典的算法題——每日溫度。這道題在 LeetCode 上被標記為中等難度&#xff0c;要求我們找到一個數組&#xff0c;其中每個元素表示從當前天開始&#xff0c;下一個更高溫度出現的天數。如果之后沒有更…

《仿盒馬》app開發技術分享-- 商品搜索頁(頂部搜索bar熱門搜索)(端云一體)

開發準備 隨著開發功能的逐漸深入&#xff0c;我們的應用逐漸趨于完善&#xff0c;現在我們需要繼續在首頁給沒有使用按鈕以及組件添加對應的功能&#xff0c;這一節我們要實現的功能是商品搜索頁面&#xff0c;這個頁面我們從上到下開始實現功能&#xff0c;首先就是一個搜索…