題目:242.有效的字母異位詞
思路:
1.ASCII和雜湊函式,存入陣列,比較陣列相等否
2.首先選擇資料結構,題目只有小寫字母,ASCII連續,選用陣列,一個字串遍歷,在雜湊陣列中存入字母出現頻率,第二個字串遍歷,做減法。(不需要記ASCII,直接減字母,編譯器自己算)
時間複雜度: O(n)
空間複雜度: O(1)
坑:
無
補充:
雜湊表理論基礎
- 雜湊表是hash table 又叫雜湊表, 多用於快速判斷某意思元素是否在集合裡。(陣列是一個雜湊表。)
- 雜湊函式hash function把 實際的目標 對映到 雜湊表上。
- 雜湊碰撞(衝突) 實際目標對映到了相同索引下標的位置。解決方法:
①拉鍊法:衝突的元素 儲存在連結串列中
②線性探測法:要保證tableSize 大於dataSize,衝突的元素 儲存在衝突位置往後的空位上。
常見的雜湊結構 - 陣列
- set(集合)
- map(對映)
set和map的底層實現及優劣表
集合set | 底層實現 | 是否有序 | 數值是否可以重複 | 能否更改數值 | 查詢效率 | 增刪效率 |
---|---|---|---|---|---|---|
std::set | 紅黑樹 | 有序 | 否 | 否 | O(log n) | O(log n) |
std::multiset | 紅黑樹 | 有序 | 是 | 否 | O(logn) | O(logn) |
std::unordered_set | 雜湊表 | 無序 | 否 | 否 | O(1) | O(1) |
使用集合來解決雜湊問題的時候,優先使用unordered_set,因為它的查詢和增刪效率是最優的,
如果需要集合是有序的,那麼就用set,
如果要求不僅有序還要有重複資料的話,那麼就用multiset。
對映map | 底層實現 | 是否有序 | 數值是否可以重複 | 能否更改數值 | 查詢效率 | 增刪效率 |
---|---|---|---|---|---|---|
std::map | 紅黑樹 | key有序 | key不可重複 | key不可修改 | O(logn) | O(logn) |
std::multimap | 紅黑樹 | key有序 | key可重複 | key不可修改 | O(log n) | O(log n) |
std::unordered_map | 雜湊表 | key無序 | key不可重複 | key不可修改 | O(1) | O(1) |
紅黑樹
紅黑樹是一種平衡二叉搜尋樹,所以key值是有序的,但key不可以修改,改動key值會導致整棵樹的錯亂,所以只能刪除和增加。
題目:349.兩個陣列的交集
思路:
- 類似上題,使用陣列,根據元素的數值,存入陣列對應下標中 但如果數值很大,對映到陣列下標就不合適。
- 該題去重,則選擇unordered_set
時間複雜度: O(n + m) m 是最後要把 set轉成vector
空間複雜度: O(n)
坑:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size()<nums2.size()){
nums1.swap(nums2);
}
unordered_set<int> hash_set(nums1.begin(),nums1.end());
unordered_set<int> result_set;
for(int num: nums2){
if(hash_set.find(num)!=hash_set.end()){
result_set.insert(num);
//在集合hash_set中使用find函式查詢num,找到返回一個指向該元素的正向迭代器,反之,返回一個類似end()的迭代器
//找到則將該元素存入結果集合result_set中
}
}
return vector<int>(result_set.begin(),result_set.end());
//因為函式返回型別是vector 所以轉換一下型別
}
};
補充:
set集合
C++ STL unordered_set容器
成員方法 | 功能 |
---|---|
find(key) | 查詢以值為 key 的元素,如果找到,則返回一個指向該元素的正向迭代器;反之,則返回一個指向容器中最後一個元素之後位置的迭代器(一個與end() 方法相同的迭代器)。 |
count(key) | 在容器中查詢值為 key 的元素的個數。 |
empty() | 若容器為空,則返回 true;否則 false。 |
size() | 返回當前容器中存有元素的個數。 |
範圍for迴圈
範圍迴圈:
for (型別 element : myVector) {
std::cout << element << " ";
}
題目:202.快樂數
思路:
對n取餘存入unordered_set 然後判斷和是否為1,題目說可能無限迴圈,不知怎麼判斷
- 無限迴圈是sum會重複出現 ,所以將每次迴圈的sum存入sums_set, 查詢是否存在。
2.看leetcode題解:雙指標
坑:
1.數位分離,求平方和,可以簡單的while和sum,不用多一步將個個數位上的值存入nums_set
2. % 是整數取餘,/ 是除號
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> sums_set;
int sum = 0;
while (sum != 1) {
sum=0; //錯誤,sum 沒有更新為0;
while (n ) {// 錯誤 while的迴圈判斷條件 不是n/10,這樣會少判斷元素
sum+=(n%10)*(n%10);
n = n / 10;
}
if(sums_set.find(sum)!=sums_set.end()){
return false;
}else{
sums_set.insert(sum);
}
n=sum;
}
return true;
}
};
題目:1.兩數之和
思路:
- 暴力法,列舉陣列中的每一個數 x,尋找陣列中是否存在 target - x。遍歷,與目標值作差,在陣列中尋找差值
- 升級,方法一時間複雜度較高在於,target-1的遍歷, 所以將遍歷過的值x和下標儲存到一個集合,之後遍歷的時候來詢問這個集合 ,target-x是否遍歷過。因為需要儲存值和下標 所以選用map,因為無序,-》unordered_map