程式碼隨想錄第6天 | ●雜湊表理論基礎●242.有效的字母異位詞●349. 兩個陣列的交集●202. 快樂數●1. 兩數之和

跳圈發表於2024-06-12

題目:242.有效的字母異位詞

思路:

1.ASCII和雜湊函式,存入陣列,比較陣列相等否
2.首先選擇資料結構,題目只有小寫字母,ASCII連續,選用陣列,一個字串遍歷,在雜湊陣列中存入字母出現頻率,第二個字串遍歷,做減法。(不需要記ASCII,直接減字母,編譯器自己算)
時間複雜度: O(n)
空間複雜度: O(1)

坑:

補充:

雜湊表理論基礎

  1. 雜湊表是hash table 又叫雜湊表, 多用於快速判斷某意思元素是否在集合裡。(陣列是一個雜湊表。)
  2. 雜湊函式hash function把 實際的目標 對映到 雜湊表上。
  3. 雜湊碰撞(衝突) 實際目標對映到了相同索引下標的位置。解決方法:
    ①拉鍊法:衝突的元素 儲存在連結串列中
    ②線性探測法:要保證tableSize 大於dataSize,衝突的元素 儲存在衝突位置往後的空位上。
    常見的雜湊結構
  4. 陣列
  5. set(集合)
  6. 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.兩個陣列的交集

思路:

  1. 類似上題,使用陣列,根據元素的數值,存入陣列對應下標中 但如果數值很大,對映到陣列下標就不合適。
  2. 該題去重,則選擇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,題目說可能無限迴圈,不知怎麼判斷

  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.兩數之和

思路:

  1. 暴力法,列舉陣列中的每一個數 x,尋找陣列中是否存在 target - x。遍歷,與目標值作差,在陣列中尋找差值
  2. 升級,方法一時間複雜度較高在於,target-1的遍歷, 所以將遍歷過的值x和下標儲存到一個集合,之後遍歷的時候來詢問這個集合 ,target-x是否遍歷過。因為需要儲存值和下標 所以選用map,因為無序,-》unordered_map

坑:

補充:

今日總結

相關文章