【哈希表】(二) 实际应用 - 哈希集合

目录

一、哈希集 - 用法

二、使用哈希集查重

三、存在重复元素

3.1 题目要求

3.2 解决过程

四、只出现一次的数字

4.1 题目要求

4.2 解决过程

五、两个数组的交集

5.1 题目要求

5.2 解决过程

六、快乐数

6.1 题目要求

6.2 解决过程


参考文献:https://leetcode-cn.com/leetbook/read/hash-table/xh7j6v/


一、哈希集 - 用法

// C++ implementation

#include <unordered_set>                // 0. include the library

int main() {
    // 1. initialize a hash set
    unordered_set<int> hashset;   
    // 2. insert a new key
    hashset.insert(3);
    hashset.insert(2);
    hashset.insert(1);
    // 3. delete a key
    hashset.erase(2);
    // 4. check if the key is in the hash set
    if (hashset.count(2) <= 0) {
        cout << "Key 2 is not in the hash set." << endl;
    }
    // 5. get the size of the hash set
    cout << "The size of hash set is: " << hashset.size() << endl; 
    // 6. iterate the hash set
    for (auto it = hashset.begin(); it != hashset.end(); ++it) {
        cout << (*it) << " ";
    }
    cout << "are in the hash set." << endl;
    // 7. clear the hash set
    hashset.clear();
    // 8. check if the hash set is empty
    if (hashset.empty()) {
        cout << "hash set is empty now!" << endl;
    }
}
# Python implementation

# 1. initialize the hash set
hashset = set() 
# 2. add a new key
hashset.add(3)
hashset.add(2)
hashset.add(1)
# 3. remove a key
hashset.remove(2)
# 4. check if the key is in the hash set
if (2 not in hashset):
    print("Key 2 is not in the hash set.")
# 5. get the size of the hash set
print("Size of hashset is:", len(hashset)) 
# 6. iterate the hash set
for x in hashset:
    print(x, end=" ")
print("are in the hash set.")
# 7. clear the hash set
hashset.clear()                         
print("Size of hashset:", len(hashset))

参考文献:https://leetcode-cn.com/leetbook/read/hash-table/xhge27/


二、使用哈希集查重

/*
 * Template for using hash set to find duplicates by C++.
 */
bool findDuplicates(vector<Type>& keys) {
    // Replace Type with actual type of your key
    unordered_set<Type> hashset;
    // 范围 for 循环
    for (Type key : keys) {
        if (hashset.count(key) > 0) {
            return true;
        }
        hashset.insert(key);
    }
    return false;
}

参考文献:https://leetcode-cn.com/leetbook/read/hash-table/xhzxa5/


三、存在重复元素

3.1 题目要求

3.2 解决过程

个人实现

法一:哈希集合 - set 实现。空间复杂度 O(n),时间复杂度 O(n)。

2020/08/23 - 85.06% (44ms)

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        hashset = set()
        for i in range(len(nums)):
            if nums[i] in hashset:
                return True
            hashset.add(nums[i])
        return False

法二:哈希映射 - dict 实现。空间复杂度 O(n),时间复杂度 O(n)。

2020/08/23 - 48.28% (52ms)

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        hashmap = dict()
        for i in range(len(nums)):
            if hashmap.get(nums[i]) == 1:  # dict.get() 比 dict[i] 更好
                return True
            hashmap[nums[i]] = 1
        return False

法三:哈希映射 - collections.Counter 实现。关于 Counter 类详见 链接

2020/08/23 - 69.11% (48ms)

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        if len(nums) < 2:
            return False
        
        counter = collections.Counter(nums)
        if counter.most_common(1)[0][1] > 1:
            return True
        return False

法四:数组排序 + 滑动窗口。空间复杂度 O(n),时间复杂度 O(nlogn)。

2020/08/23 - 69.11% (48ms)

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        if len(nums) < 2:
            return False
        
        sorted_nums = sorted(nums)  # 数组排序, 如果 nums.sort() 空间复杂度就是 O(1)
        for i in range(len(nums)-1):
            if sorted_nums[i] == sorted_nums[i+1]:
                return True
        return False

官方实现与说明

// Java implementation
public boolean containsDuplicate(int[] nums) {
    for (int i = 0; i < nums.length; ++i) {
        for (int j = 0; j < i; ++j) {
            if (nums[j] == nums[i]) return true;  
        }
    }
    return false;
}
// Time Limit Exceeded


// Java implementation
public boolean containsDuplicate(int[] nums) {
    Arrays.sort(nums);
    for (int i = 0; i < nums.length - 1; ++i) {
        if (nums[i] == nums[i + 1]) return true;
    }
    return false;
}


// Java implementation
public boolean containsDuplicate(int[] nums) {
    Set<Integer> set = new HashSet<>(nums.length);
    for (int x: nums) {
        if (set.contains(x)) return true;
        set.add(x);
    }
    return false;
}

参考文献

https://leetcode-cn.com/leetbook/read/hash-table/xhzjp6/

https://leetcode-cn.com/problems/contains-duplicate/solution/cun-zai-zhong-fu-yuan-su-by-leetcode/


四、只出现一次的数字

4.1 题目要求

4.2 解决过程

个人实现

法一:哈希集合 - set 实现。遍历数组,将出现过一次的元素加入哈希集合,将出现过两次的元素移除哈希集合,那么最后剩下的元素即为只出现一次的数字。空间复杂度 O(n),时间复杂度 O(n)。

2020/08/23 - 97.83% (36ms) - 

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        hashset = set()  # 哈希集合 (如果用两个哈希集合最后作差就会比较麻烦)
        for i in range(len(nums)):
            if nums[i] not in hashset:
                hashset.add(nums[i])  # 添加出现过 1 次的元素
            else:
                hashset.remove(nums[i])  # 移除出现过 2 次的元素  # set.discard() 也行
        return hashset.pop()  # 剩下唯一元素即为目标元素

法二:哈希映射 - Counter 实现

2020/08/23 - 61.54% (48ms)

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        counter = collections.Counter(nums)
        return counter.most_common()[-1][0]

法三:数组排序 + 滑动窗口。空间复杂度 O(n),时间复杂度 O(nlogn)。

2020/08/23 - 92.35% (40ms)

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        
        sorted_nums = sorted(nums)  # 数组排序, 如果 nums.sort() 空间复杂度就是 O(1)
        for i in range(0, len(nums)-1, 2):
            if sorted_nums[i] != sorted_nums[i+1]:
                return sorted_nums[i]
        return sorted_nums[-1]

法四:位运算 - 异或 XOR。利用异或运算相同为 0 相异为 1 的性质,遍历整个数组依次异或,最终即可得到唯一元素。从而满足题目要求的 空间复杂度 O(1),时间复杂度 O(n)

2020/08/23 - 92.35% (40ms) - 最佳

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        num = nums[0]
        for i in range(1, len(nums)):
            num = num ^ nums[i]
        return num

官方实现与说明

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        return reduce(lambda x, y: x ^ y, nums)

参考文献

https://leetcode-cn.com/leetbook/read/hash-table/xhsyr2/

https://leetcode-cn.com/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/


五、两个数组的交集

5.1 题目要求

5.2 解决过程

个人实现

法一:交集运算。强制类型转换后,执行交集运算。似乎一时想不出更简单的方法了。

2020/08/23 - 95.63% (52ms)

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return set(nums1) & set(nums2)  # return set(nums1).intersection(set(nums2))

法二:哈希集合。空间复杂度 O(min(m, n)),时间复杂度 O(m+n)。

2020/11/02 - 99.50% (44ms) - 最佳

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        hashset = set()
        for i in nums1:
            hashset.add(i)
        
        result = []
        for j in nums2:
            if j in hashset:
                result.append(j)
                hashset.remove(j)
        
        return result

 官方实现与说明

class Solution:
    def set_intersection(self, set1, set2):
        return [x for x in set1 if x in set2]
        
    def intersection(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """  
        set1 = set(nums1)
        set2 = set(nums2)
        
        if len(set1) < len(set2):
            return self.set_intersection(set1, set2)
        else:
            return self.set_intersection(set2, set1)

2020/08/23 - 74.68% (60ms) 


class Solution:
    def intersection(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """  
        set1 = set(nums1)
        set2 = set(nums2)
        return list(set2 & set1)

参考文献

https://leetcode-cn.com/leetbook/read/hash-table/xh4sec/

https://leetcode-cn.com/problems/intersection-of-two-arrays/solution/liang-ge-shu-zu-de-jiao-ji-by-leetcode/


六、快乐数

6.1 题目要求

6.2 解决过程

官方实现与说明

class Solution:
    def isHappy(self, n: int) -> bool:
        def get_next(n):
            total_sum = 0
            while n > 0:
                n, digit = divmod(n, 10)
                total_sum += digit ** 2
            return total_sum

        seen = set()
        while n != 1 and n not in seen:
            seen.add(n)
            n = get_next(n)

        return n == 1

2020/08/24 - 91.55% (40ms)


class Solution:
    def isHappy(self, n: int) -> bool:  
        def get_next(number):
            total_sum = 0
            while number > 0:
                number, digit = divmod(number, 10)
                total_sum += digit ** 2
            return total_sum

        slow_runner = n
        fast_runner = get_next(n)
        while fast_runner != 1 and slow_runner != fast_runner:
            slow_runner = get_next(slow_runner)
            fast_runner = get_next(get_next(fast_runner))
        return fast_runner == 1

 2020/08/24 - 91.55% (40ms)


class Solution:
    def isHappy(self, n: int) -> bool:
        cycle_members = {4, 16, 37, 58, 89, 145, 42, 20}

        def get_next(number):
            total_sum = 0
            while number > 0:
                number, digit = divmod(number, 10)
                total_sum += digit ** 2
            return total_sum

        while n != 1 and n not in cycle_members:
            n = get_next(n)

        return n == 1

2020/08/24 - 97.47% (36ms) - 最佳

参考文献

https://leetcode-cn.com/leetbook/read/hash-table/xh1k9i/

https://leetcode-cn.com/problems/happy-number/solution/kuai-le-shu-by-leetcode-solution/

https://leetcode-cn.com/problems/happy-number/solution/shi-yong-kuai-man-zhi-zhen-si-xiang-zhao-chu-xun-h/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值