代码随想录算法训练营 Day 6

3 minute read

Published:

Q1. LeetCode 454

思路:用哈希表存储数组nums1和nums2所有可能的和与该和出现的次数。然后再将数组nums3和nums4中的数字相加,如果-(num3 + num4)出现在哈希表中,则最终结果加上对应的值

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hashmap = {}
        for num1 in nums1:
            for num2 in nums2:
                s = num1 + num2
                hashmap[s] = hashmap.get(s, 0) + 1
        
        res = 0
        for num3 in nums3:
            for num4 in nums4:
                s = num3 + num4
                if -s in hashmap:
                    res += hashmap[-s]
        
        return res

复杂度分析

时间复杂度:O($n^2$) 空间复杂度:O($n^2$)

Q2. LeetCode 383

解法1: 利用哈希表统计magazine中的各个字母出现次数,然后遍历ransomNote,如果当前字母在哈希表中,则将其值减1。当减到0时,在哈希表中将其删掉。如果遍历过程中出现当前字母未出现在哈希表中,返回False;否则返回True

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        if len(ransomNote) > len(magazine):
            return False

        hashmap = {}
        for c in magazine:
            hashmap[c] = hashmap.get(c, 0) + 1
        
        for c in ransomNote:
            if c not in hashmap:
                return False
            hashmap[c] -= 1
            if hashmap[c] == 0:
                del hashmap[c]
        
        return True

解法2: 用数组替代哈希表

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        if len(ransomNote) > len(magazine):
            return False

        count = [0] * 26
        for c in magazine:
            idx = ord(c) - ord('a')
            count[idx] += 1
        
        for c in ransomNote:
            idx = ord(c) - ord('a')
            if count[idx] == 0:
                return False
            count[idx] -= 1
        
        return True

复杂度分析

时间复杂度:O($n$) 空间复杂度:O(1)

Take some notes

使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以在使用哈希表之前,需要考虑数组是否可行

Q3. LeetCode 15

解法1:第一层循环确定最小数字a,第二层循环确定最大数字c,如果b存在,则必定在两数之间。利用哈希表存储第二次循环中出现的数字,若哈希表中能找到该数字,则组合为结果之一

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        hashmap = {}
        nums.sort()
        res = []

        for i in range(len(nums)):
            if nums[i] > 0:
                break
            
            # 当前数字和前一个数字相同,则其对应的组合也和之前一致,因此可以跳过
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            appeared_num = {}
            for j in range(i + 1, len(nums)):
                # 需要判断连续三个数是否相同,而非两个数
                if j > i + 2 and nums[j] == nums[j - 1] == nums[j - 2]:
                    continue

                diff = - (nums[i] + nums[j])
                if diff in appeared_num:
                    res.append([nums[i], nums[j], diff])
                    appeared_num.pop(diff)
                else:
                    appeared_num[nums[j]] = j
        
        return res

复杂度分析

时间复杂度:O($n^2$) 空间复杂度:O($n$)

难点

注意对于三个数字的去重方式,特别是对于c的去重,需要判断连续三个数字是否相同


解法2: 第一层循环确定最小数字a,利用双指针分别求b,c

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()

        for i in range(len(nums)):
            if nums[i] > 0:
                break
            
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            j = i + 1
            k = len(nums) - 1

            while j < k:
                s = nums[i] + nums[j] + nums[k]
                
                if s < 0:
                    j += 1
                elif s > 0:
                    k -= 1
                else:
                    res.append([nums[i], nums[j], nums[k]])

                    # 对b去重
                    while j < k and nums[j + 1] == nums[j]:
                        j += 1
                    
                    # 对c去重
                    while j < k and nums[k - 1] == nums[k]:
                        k -= 1

                    j += 1
                    k -= 1

        return res

复杂度分析

时间复杂度:O($n^2$) 空间复杂度:O(1)

Q4. LeetCode 18

思路:与Q3类似,只是需要再加一层循环确定第二个数字

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        res = []
        nums.sort()

        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            for j in range(i + 1, len(nums)):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue

                k = j + 1
                l = len(nums) - 1

                while k < l:
                    s = nums[i] + nums[j] + nums[k] + nums[l]

                    if s < target:
                        k += 1
                    elif s > target:
                        l -= 1
                    else:
                        res.append([nums[i], nums[j], nums[k], nums[l]])

                        while k < l and nums[k + 1] == nums[k]:
                            k += 1

                        while k < l and nums[l - 1] == nums[l]:
                            l -= 1

                        k += 1
                        l -= 1
        
        return res

复杂度分析

时间复杂度:O($n^3$) 空间复杂度:O($1$)