網(wǎng)站不備案支付寶接口大二網(wǎng)絡營銷實訓報告
哈希表
- 理論知識(本文來自于代碼隨想錄摘抄)
- 什么是哈希
- 常見的三種哈希結(jié)
- 數(shù)組:
- set:
- map:
- 其他常用方法或者技巧(自己總結(jié)的)
- 練習題和講解
- 有效的字母移位詞
- 349. 兩個數(shù)組的交集
- 1. 兩數(shù)之和
- 454. 四數(shù)相加 II
- 15. 三數(shù)之和
- 總結(jié)
理論知識(本文來自于代碼隨想錄摘抄)
什么是哈希
哈希表中關鍵碼就是數(shù)組的索引下標,然后通過下標直接訪問數(shù)組中的元素,如下圖所示:
那么哈希表能解決什么問題呢,一般哈希表都是用來快速判斷一個元素是否出現(xiàn)集合里。
常見的三種哈希結(jié)
當我們想使用哈希法來解決問題的時候,我們一般會選擇如下三種數(shù)據(jù)結(jié)構(gòu)。
數(shù)組
set (集合)
map(映射)
數(shù)組:
當目標的范圍是已知的,是小的,我們會使用數(shù)組。(經(jīng)常使用,所以少介紹。)
set:
map:
其他常用方法或者技巧(自己總結(jié)的)
10,用來判斷某個值是否存在哈希表中:containsKey()
if(result.containsKey(temp)){}
練習題和講解
有效的字母移位詞
使用int
前置知識:
字母a-z,A-Z的ASCII碼是連續(xù)的。
所以’a’-‘a(chǎn)’=0;‘z’-‘a(chǎn)’=25;
class Solution {public boolean isAnagram(String s, String t) {int[] arr=new int[26]; //用來存儲26個字母出現(xiàn)的次數(shù)for(int i=0;i<s.length();i++){ //字符串用length()方法,數(shù)組為length。因為對于字符串,length是方法,數(shù)組是內(nèi)置屬性。 arr[s.charAt(i)-'a']++; //charAt(i)獲取字符串中i位置的字符。 我們在對于的下標的位置+1.比如出現(xiàn)z,則是'z'-'a',在25這個位置+1.};for(int i=0;i<t.length();i++){arr[t.charAt(i)-'a']--; //目的同樣,在對應位置-1,抵消s字符串中出現(xiàn)的字母。};for(int a:arr){ //增強for循環(huán)方法。if(a!=0){ //進行判斷,如果不等0,證明兩個里面的出現(xiàn)字母的數(shù)量不一致。return false;}}return true;}
}
349. 兩個數(shù)組的交集
349. 兩個數(shù)組的交集
使用set
class Solution {public int[] intersection(int[] nums1, int[] nums2) {if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {return new int[0];} //首先判斷是否為空Set<Integer> set1 = new HashSet<>(); //使用set可以直接去重Set<Integer> resSet = new HashSet<>();//遍歷數(shù)組1for (int i : nums1) {set1.add(i); }//遍歷數(shù)組2的過程中判斷哈希表中是否存在該元素for (int i : nums2) {if (set1.contains(i)) { //contains() 判斷這個值是否在哈希表中resSet.add(i);}}//另外申請一個數(shù)組存放setRes中的元素,最后返回數(shù)組int[] arr = new int[resSet.size()];int j = 0;for(int i : resSet){arr[j++] = i;}return arr;}
}
1. 兩數(shù)之和
1. 兩數(shù)之和
使用map(需要存放 key value)
class Solution {public int[] twoSum(int[] nums, int target) {// 創(chuàng)建一個 HashMap 來存儲數(shù)字及其對應的索引Map<Integer, Integer> map = new HashMap<>();int n = nums.length;// 遍歷數(shù)組for (int i = 0; i < n; i++) {// 計算當前元素的補數(shù)int temp = target - nums[i];// 檢查補數(shù)是否在 HashMap 中if (map.containsKey(temp)) {// 找到結(jié)果,那么返回當前索引和補數(shù)的索引return new int[]{map.get(temp), i};}// 如果沒有找到補數(shù),就把當前數(shù)字和它的索引放入 HashMapmap.put(nums[i], i);}// 如果沒有找到,返回一個空數(shù)組,考慮到題目保證有解這里可以省略return new int[]{};}
}
454. 四數(shù)相加 II
454. 四數(shù)相加 II
class Solution {public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {int res = 0;//不僅要保存值,還需要保存其出現(xiàn)次數(shù),所以使用map(key,value)來進行存儲數(shù)據(jù)。Map<Integer, Integer> map = new HashMap<Integer, Integer>();//統(tǒng)計兩個數(shù)組中的元素之和,同時統(tǒng)計出現(xiàn)的次數(shù),放入mapfor (int i : nums1) {for (int j : nums2) {int sum = i + j;map.put(sum, map.getOrDefault(sum, 0) + 1);//getOrDefault這個的意思是,如果存在,返回存在的值,不存在返回default0}}//統(tǒng)計剩余的兩個元素的和,在map中找是否存在相加為0的情況,同時記錄次數(shù)for (int i : nums3) {for (int j : nums4) {//因為本題不去重,所以有不同組合,需要統(tǒng)計的值為 res+sum(對應的值);res += map.getOrDefault(0 - i - j, 0);}}return res;}
}
15. 三數(shù)之和
15. 三數(shù)之和
使用哈希集合:
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();Arrays.sort(nums);for (int i = 0; i < nums.length; i++) {// 如果第一個元素大于零,不可能湊成三元組if (nums[i] > 0) {return result;}// 三元組元素a去重if (i > 0 && nums[i] == nums[i - 1]) {continue;}HashSet<Integer> set = new HashSet<>();for (int j = i + 1; j < nums.length; j++) {// 三元組元素b去重if (j > i + 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2]) {continue;}int c = -nums[i] - nums[j];if (set.contains(c)) {result.add(Arrays.asList(nums[i], nums[j], c));set.remove(c); // 三元組元素c去重} else {set.add(nums[j]);}}}return result;}
}
使用雙指針(更為推薦)
class Solution {public List<List<Integer>> threeSum(int[] nums) {//二維集合,因為不止一個集合List<List<Integer>> ans=new ArrayList();int len=nums.length;//如果值小于3,則沒有意義if(len<3||nums==null) return ans;//排序,更方便我們雙指針的移動Arrays.sort(nums);//定i的位置,然后動left和right兩個指針的位置來湊0for(int i=0;i<len;i++){//如果第一個i都>0,則不可能三數(shù)之和為0if(nums[i]>0) break;//題目去重,所以我們判斷前一位值如果等于后一位,則跳過。if(i>0&&nums[i]==nums[i-1]) continue;//定義左右指針 int L=i+1;int R=len-1; while(L<R){int sum =nums[i]+nums[R]+nums[L];//如果相等,則添加進入二維數(shù)組中if(sum==0){ans.add(Arrays.asList(nums[i],nums[L],nums[R]));//歸零while(L<R&& nums[L]==nums[L+1]) L++;while(L>R&& nums[R]==nums[R-1]) R--;L++;R--;}//和小,就左指針右移,和大,就右指針左移else if(sum<0)L++;else if(sum>0)R--;}}//返回二維數(shù)組。return ans;}
}
總結(jié)
哈希表理論基礎
在關于哈希表,你該了解這些! (opens new window)中,我們介紹了哈希表的基礎理論知識,不同于枯燥的講解,這里介紹了都是對刷題有幫助的理論知識點。
一般來說哈希表都是用來快速判斷一個元素是否出現(xiàn)集合里。
對于哈希表,要知道哈希函數(shù)和哈希碰撞在哈希表中的作用。
哈希函數(shù)是把傳入的key映射到符號表的索引上。
哈希碰撞處理有多個key映射到相同索引上時的情景,處理碰撞的普遍方式是拉鏈法和線性探測法。
接下來是常見的三種哈希結(jié)構(gòu):
數(shù)組
set(集合)
map(映射)
在C++語言中,set 和 map 都分別提供了三種數(shù)據(jù)結(jié)構(gòu),每種數(shù)據(jù)結(jié)構(gòu)的底層實現(xiàn)和用途都有所不同,在關于哈希表,你該了解這些! (opens new window)中我給出了詳細分析,這一知識點很重要!
例如什么時候用std::set,什么時候用std::multiset,什么時候用std::unordered_set,都是很有考究的。
只有對這些數(shù)據(jù)結(jié)構(gòu)的底層實現(xiàn)很熟悉,才能靈活使用,否則很容易寫出效率低下的程序。