昨日回顧
昨天,我們針對Java中的 HashMap 、HashSet ,和Python中的 dict & set 使用,進行了分類學習,并按照表格總結了不同數據結構所包含的方法與使用場景。在這兩個數據結構上,Python與Java倒是大同小異,沒有過多的差別。
之后,通過兩道題目簡單了解了這類題型的解題方式。那么今天,我們在此基礎上進一步來熟悉下哈希表解題的運用。
先來一道閱讀理解題目熱熱身子吧!
劍指OfferII034.外星語言是否排序
https://leetcode-cn.com/problems/lwyVBB/solution/shua-chuan-jian-zhi-offer-day16-ha-xi-bi-mtik/
難度:簡單
題目:
某種外星語也使用英文小寫字母,但可能順序 order 不同。字母表的順序(order)是一些小寫字母的排列。
給定一組用外星語書寫的單詞 words,以及其字母表的順序 order,只有當給定的單詞在這種外星語中按字典序排列時,
返回 true;否則,返回 false。
提示:
- 1 <= words.length <= 100
- 1 <= words[i].length <= 20
- order.length == 26
- 在 words[i] 和 order 中的所有字符都是英文小寫字母。
示例:
示例 1:
輸入:words = ["hello","leetcode"], order = "hlabcdefgijkmnopqrstuvwxyz"
輸出:true
解釋:在該語言的字母表中,'h' 位于 'l' 之前,所以單詞序列是按字典序排列的。
示例 2:
輸入:words = ["word","world","row"], order = "worldabcefghijkmnpqstuvxyz"
輸出:false
解釋:在該語言的字母表中,'d' 位于 'l' 之后,那么 words[0] > words[1],因此單詞序列不是按字典序排列的。
示例 3:
輸入:words = ["apple","app"], order = "abcdefghijklmnopqrstuvwxyz"
輸出:false
解釋:當前三個字符 "app" 匹配時,第二個字符串相對短一些,然后根據詞典編纂規則 "apple" > "app",
因為 'l' > '?',其中 '?' 是空白字符,定義為比任何其他字符都小(更多信息)。
分析
坦白說這是一道閱讀理解題目,能仔細看清楚題目要求的比較規則,就差不多已經通過了...
根據外星人的英文字母順序,比較words列表中的每個單詞是按照 升序 排列的,則返回 true ,否則返回 false
那么如何比較每個單詞的順序呢?通過觀察示例,我們了解到其實就是針對單詞去按位比較,在order中的順序。
這里注意下,如果長度不夠,以空補充,空即無窮小。
理解了上面的思路,就可以開始編寫解題了:
- 比較單詞的出現順序,可以用到哈希表去快速獲取單詞的排序下標,既然是哈希表專題,就不用ascii配合數組模擬哈希了。
- 然后就要開始單詞的逐個比較了,這個可以參考冒泡排序的方式兩兩比較,a<b且b<c,則肯定a < c
- 如果遇到left[index] > right[index] 直接返回False,無需其他操作了
- 如果遇到left[index] < right[index] 類似 109 < 110 十位已經小了,后面就沒必要看了,直接break接著比較下一個。
- 如果第三步一直沒有false,最終返回true即可。
來看看具體解題吧:
解題:
Python:
class Solution:
def isAlienSorted(self, words: List[str], order: str) -> bool:
dic = {j: i for i, j in enumerate(order)}
for i in range(len(words) - 1):
w1, w1_len = words[i], len(words[i])
w2, w2_len = words[i + 1], len(words[i + 1])
for idx in range(max(w1_len, w2_len)):
w1_idx = -1 if idx >= w1_len else dic[w1[idx]]
w2_idx = -1 if idx >= w2_len else dic[w2[idx]]
if w1_idx > w2_idx:
return False
if w1_idx < w2_idx:
break
return True
Java:
class Solution {
public boolean isAlienSorted(String[] words, String order) {
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < order.length(); i++) {
map.put(order.charAt(i), i);
}
for (int i = 0; i < words.length - 1; i++) {
String w1 = words[i];
int w1_len = w1.length();
String w2 = words[i + 1];
int w2_len = w2.length();
for (int j = 0; j < Math.max(w1_len, w2_len); j++) {
int idx_w1 = j > w1_len ? -1 : map.get(w1.charAt(j));
int idx_w2 = j > w2_len ? -1 : map.get(w2.charAt(j));
if (idx_w1 > idx_w2) return false;
if (idx_w1 < idx_w2) break;
}
}
return true;
}
}
這道閱讀理解的題目,是不是一下子把自信就給找回來了?
雖然說哈希表是算法中最常用的數據結構,但是它卻比較比較簡單而純粹,當你需要優化時間的時候,就使用它來把時間轉換為空間。就是這么簡單....
注意:但下面我要不按套路出牌的給大家分享一道很特別的哈希表題目了,快來看看吧。
525.連續數組
難度:中等
題目:
給定一個二進制數組 nums , 找到含有相同數量的 0 和 1 的最長連續子數組,
并返回該子數組的長度。
示例:
示例 1:
輸入: nums = [0,1]
輸出: 2
說明: [0, 1] 是具有相同數量0和1的最長連續子數組。
示例 2:
輸入: nums = [0,1,0]
輸出: 2
說明: [0, 1] (或 [1, 0]) 是具有相同數量0和1的最長連續子數組。
示例 3:
輸入: nums = [0,0,1,0,0,0,1,1]
輸出: 6
說明: [1,0,0,0,1,1] 是具有相同數量0和1的最長連續子數組。
分析
不得不說,如果這道題的用例是-1 和 1,那么大家可能還比較容易產生思路,可惜這道題是0 和 1,我們需要轉化一下
為什么要轉化為-1 和 1呢?
因為如果具有相同的-1 和 1,由于它們數目相同,所以這些數字加起來就等于0。
加起來,看到這個關鍵字是不是該想到我們在數組中學習到的前綴和了?
我們采用前綴的方式,當前綴和的某一個數和之前的某一個位置的數字相等,那是不是在這段數組之間出現了相同數目的-1 和 1,所以抵消為0 了。
配合Hash表的使用,我們可以快速記錄 {前綴和: 下標} 的關系, 由于可能存在nums前N數字和剛好滿足條件的情況,所以我們預制燒餅節點{0,-1},來規避該問題。
循環判斷是否在字典中存在前綴和一樣的鍵,并不斷判斷最長符合題意的連續數組,最終返回即可。
千言萬語化作一張圖,一看就明白了:
在index = 7的位置前綴和為 -2, 而哈希表中在index = 1的位置前綴和也為-2。這便是我們通過前綴和+哈希表來解題的思路了。
解題:
Python:
class Solution:
def findMaxLength(self, nums):
d = {0: -1}
ret = pre_sum = 0
for i, num in enumerate(nums):
pre_sum += 1 if num == 1 else -1
pre_index = d.get(pre_sum, i)
if pre_index == i:
d[pre_sum] = i
else:
ret = max(ret, i - pre_index)
return ret
Java:
class Solution {
public int findMaxLength(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int pre_sum = 0;
int ret = 0;
for (int i = 0; i < nums.length; i++) {
pre_sum += nums[i] == 1 ? 1 : -1;
int pre_index = map.getOrDefault(pre_sum, i);
if (pre_index == i) {
map.put(pre_sum, i);
} else {
ret = Math.max(ret, i - pre_index);
}
}
return ret;
}
}
個人感覺 525.連續數組 是一道比較綜合的算法題目,涉及到我們之前學習的前綴思維,與本章的哈希表的結合。
反倒是 劍指 Offer II 035. 最小時間差 作為哈希表的最后一道題顯得有些不倫不類。所以這道題就留給大家作為課后作業了。
哈希表的章節就到這里了,讓我們一路向前吧!