[leetcode-python brush questions] Hash table

1. The sum of two numbers (easy)

V1 violent solution

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i, j]
        
        return []

result:
insert image description here

  • Time complexity: O(N 2 ).
  • Space complexity: O(1).

V2 hash table

Determine whether the current value is in the hash table, if not, put the difference between the target and the value into the hash table. Note: Save the value as key and the index as value, so that you can determine whether the current value is in the hash table.

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        i = 0
        hashtable = {
    
    }
        while i < len(nums):
            if nums[i] not in hashtable:
                hashtable[target - nums[i]] = i
                i += 1
            else:
                return [i, hashtable[nums[i]]]

result:
insert image description here

  • Time complexity: O(N).
  • Space complexity: O(N).

217. There are repeated elements (easy)

Given an array of integers, check whether there are duplicate elements.

The function returns true if there is a value that occurs at least twice in the array. Returns false if every element in the array is different.

V1 (stored in a list)

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        table = []
        for i in nums:
            if i not in table:
                table.append(i)
            else:
                return True
        return False

result:
insert image description here

V2 (stored in collections)

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

result:
insert image description here

V3(set())

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        return len(set(nums)) != len(nums)

The set() function creates an unordered set of non-repeating elements, which can be used for relationship testing, duplicate data removal, and calculation of intersection, difference, union, etc.

result:
insert image description here

594. Longest Harmonious Subsequence (easy)

A harmonious array is one in which the difference between the maximum and minimum values ​​of elements in an array is exactly 1.

Now, given you an integer array nums, please find the length of the longest harmonious subsequence among all possible subsequences.

A subsequence of an array is a sequence derived from an array that can be obtained by deleting some elements or not deleting elements without changing the order of the remaining elements.

V1

Use a hash table to store the number of occurrences of each element, and then traverse the hash table.

class Solution:
    def findLHS(self, nums: List[int]) -> int:
        table = {
    
    }
        for i in nums:
            if table.get(i) is None:
                table[i] = 1
            else:
                table[i] += 1
        print(table.keys())
        print(table.values())
        length = 0
        for i in table.keys():
            if i + 1 in table.keys():
                if table[i] + table[i+1] > length:
                    length = table[i] + table[i+1]
        return length

result:
insert image description here

128. The longest continuous sequence (hard)

Given an unsorted integer array nums, find the length of the longest sequence of consecutive numbers (it is not required that the elements of the sequence are consecutive in the original array).

Please design and implement an algorithm with O(n) time complexity to solve this problem.

Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-consecutive-sequence
The copyright belongs to LeetCode. For commercial reprints, please contact the official authorization, for non-commercial reprints, please indicate the source.

V1

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return 1
        table = {
    
    }
        for i in nums:
            if table.get(i) is None:
                table[i] = 1
            else:
                table[i] += 1
        print(table)
        num = sorted(table.keys())
        print(num)
        count = 1
        max_count = 1
        for i in range(len(num)-1):
            if num[i+1] == num[i] + 1:
                count += 1
                if count > max_count:
                    max_count = count
            else:
                count = 1
        return max_count

v2

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        table = set(nums)
        max_count = 0
        for i in range(len(nums)):
            if nums[i] - 1 not in table:
                count = 1
                cur = nums[i]
                while cur + 1 in table:
                    count += 1
                    cur += 1
                max_count = max(count, max_count)
        return max_count

349. Intersection of two arrays (easy)

insert image description here

V1 (mine)

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        table = set()
        out = set()
        for i in nums1:
            if i not in table:
                table.add(i)
        for j in nums2:
            if j in table:
                out.add(j)
        return list(out)

insert image description here

V2 (official)

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        set1 = set(nums1)
        set2 = set(nums2)
        return self.set_intersection(set1, set2)

    def set_intersection(self, set1, set2):
        if len(set1) > len(set2):
            return self.set_intersection(set2, set1)
        return [x for x in set1 if x in set2]

insert image description here

V3 (according to the official simplification)

It is only during the process of simplification that the official version compares the meaning of the lengths of the two collections. It is faster to cycle according to the short collection.

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
	    if not nums1 or not nums2: return []
        set1 = set(nums1)
        set2 = set(nums2)
        return [x for x in set1 if x in set2]

insert image description here

350. Intersection of Two Arrays II (easy)

insert image description here
Notice the difference between this question and the previous question. This question not only needs to find which numbers are included in the intersection, but also knows how many times these numbers are repeated.

V1 (mine)

Idea: Make a loop on each of the two lists, store the values ​​that appear and the corresponding times in the dictionary, then find the intersection of the keys of the two dictionaries, and loop append according to the minimum value of the corresponding value.

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        table1 = {
    
    }
        table2 = {
    
    }
        out = []
        for i in nums1:
            table1[i] = table1.get(i, 0) + 1
        for j in nums2:
            table2[j] = table2.get(j, 0) + 1
        key = [i for i in table1.keys() if i in table2.keys()]
        for k in key:
            for t in range(min(table1[k], table2[k])):
                out.append(k)
        return out

insert image description here

V2 (according to the official modification)

Just loop through each of the two lists once.

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        table1 = {
    
    }
        out = []
        for i in nums1:
            table1[i] = table1.get(i, 0) + 1
        for j in nums2:
            if j in table1.keys() and table1[j] > 0:
                out.append(j)
                table1[j] -= 1
        return out

insert image description here

242. Effective anagrams (easy)

insert image description here

V1 (mine)

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        table = {
    
    }
        for i in s:
            table[i] = table.get(i, 0) + 1
        for j in t:
            if j in table.keys():
                if table[j] == 0:
                    return False
                table[j] -= 1
            else:
                return False
        if sum(table.values()) == 0:
            return True
        return False

insert image description here

V2 (mine)

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        table1 = {
    
    }
        table2 = {
    
    }
        for i in s:
            table1[i] = table1.get(i, 0) + 1
        for j in t:
            table2[j] = table2.get(j, 0) + 1
        return table1 == table2

insert image description here

V3 (the solution seen in the problem solution, using Counter)

from collections import Counter

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        s_ = Counter(s)
        t_ = Counter(t)
        return s_ == t_

insert image description here
Counter is a subclass of dictionary object. The Counter() function in the collections module takes an iterator such as a list or tuple and returns a Counter dictionary. The keys of this dictionary are the only elements in this iterator, and the value of each key is the count of the iterator's elements. (Source: https://www.jianshu.com/p/cfb14ebcf371 )

202. Happy Number (easy)

insert image description here

V1 (mine)

The difficulty lies in when to output False. If you keep judging whether the sum of squares is 1 in an endless loop, the execution time will be NAN. hereA collection is set up, and all the square sum results that have occurred are put into it, when the current calculation result appears in this set, it means that the result enters a loop state, and there is no need to continue the calculation, and False is output at this time.

class Solution:
    def isHappy(self, n: int) -> bool:
        table = set()
        while 1:
            out = 0
            n = str(n)
            for i in n:
                out += int(i) * int(i)
            if out == 1:
                return True
            elif out in table:
                return False
            n = out
            table.add(n)

insert image description here

V2 (fast and slow pointer)

I read that it is done with speed pointers in the solution.

class Solution:
    def isHappy(self, n: int) -> bool:
        if n == 1:
            return True
        slow = sum([int(i)**2 for i in str(n)])
        fast = sum([int(i)**2 for i in str(slow)])
        while slow != fast:
            slow = sum([int(i)**2 for i in str(slow)])
            fast = sum([int(i)**2 for i in str(fast)])
            fast = sum([int(i)**2 for i in str(fast)])
        if slow == 1:
            return True
        else:
            return False

insert image description here

  • It seems to suddenly understand the reason why the fast pointer and the slow pointer move different distances each time in the fast and slow pointers, probably to ensure that the distance between the two pointers can take any value? Only in this way can the loop be found, otherwise the loop may not be found if the distance between the two pointers remains the same.
  • The reason for the slower speed is guessed: Once there are repeated elements, V1 can judge them at once by using the method of set judgment, while using the method of V2 fast and slow pointers, the pointers may not exactly point to two repeated elements, so it takes longer The loop time waits until the pointer reaches a specific position.
  • 判断循环就用快慢指针

205. Isomorphic strings (easy)

insert image description here

V1 (mine)

Corresponding element comparison, the value in s is used as the key of the dictionary, and the value in t is used as the value in the dictionary.

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False
        length = len(s)
        table = {
    
    }
        for i in range(length):
            if s[i] not in table.keys():
                if t[i] in table.values():
                    return False
                table[s[i]] = t[i]
            else:
                if table[s[i]] != t[i]:
                    return False
        return True

insert image description here

V2 (from the problem solution)

Compare the index of the corresponding element, and get it done with one line of code.

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        return all(s.index(s[i]) == t.index(t[i])  for i in range(len(s)))

insert image description here

451. Sort by character frequency (medium)

insert image description here
insert image description here
Note the case sensitivity.

V1 (mine)

Store the elements and times that the string s appears in the dictionary, then sort the values ​​of the dictionary, and use the list to build a new string.

class Solution:
    def frequencySort(self, s: str) -> str:
        table = {
    
    }
        s_new = []
        for i in s:
            table[i] = table.get(i,0) + 1
        new_table = sorted(table.items(),  key=lambda d: d[1], reverse=True)
        for i in new_table:
            for times in range(i[1]):
                s_new.append(i[0])
        return ''.join(s_new)

insert image description here

V2 (improved on the basis of V1)

The difference from V1 is that it does not use a list to store new strings. It is noted that repeating an element in a string can be obtained 字符串*出现次数by and +connected by .
It is more efficient to use multiplication instead of loop

class Solution:
    def frequencySort(self, s: str) -> str:
        table = {
    
    }
        s_new = ''
        for i in s:
            table[i] = table.get(i,0) + 1
        new_table = sorted(table.items(),  key=lambda d: d[1], reverse=True)
        for i in new_table:
            s_new += i[0] * i[1]  ### 只修改了这一行
        return s_new

insert image description here

V3 (using Counter)

from collections import Counter

class Solution:
    def frequencySort(self, s: str) -> str:
        return "".join(i[0] * i[1] for i in Counter(s).most_common(len(s)))

insert image description here

15. The sum of three numbers (medium)

insert image description here

V1 (mine, failed)

What I want is to divide the list into three small lists of positive, negative, and zero. The output result is either two positives and one negative, or two negatives and one positive, or zero and one positive and one negative, or all zeros. The result was not passed, so I don't want to think about it.

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        negative = []
        positive = []
        zero = []
        out = []
        for i in nums:
            if i > 0:
                positive.append(i)
            elif i < 0:
                negative.append(i)
            else:
                zero.append(i)
        for i in range(len(positive)):
            for j in range(i+1, len(positive)):
                if -(positive[i] + positive[j]) in negative:
                    t = [positive[i],positive[j],-(positive[i]+positive[j])]
                    if t not in out:
                        out.append(t)
            if zero!=[] and -positive[i] in negative:
                t = [positive[i],0,-positive[i]]
                if t not in out:
                    out.append(t)
        for i in range(len(negative)):
            for j in range(i+1, len(negative)):
                if -(negative[i] + negative[j]) in positive:
                    t = [negative[i],negative[j],-(negative[i]+negative[j])]
                    if t not in out:
                        out.append(t)
        if len(zero) >= 3:
            out.append([0,0,0])
        return out

V2 (refer to solution)

colliding pointer.
The focus is on judging duplicate values ​​in multiple places and narrowing the search scope as much as possible.

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        out = []
        for i in range(len(nums)-2):
            if nums[i] > 0:
                break
            if i > 0 and nums[i] == nums[i-1]:
                i += 1
                continue
            j, k = i + 1, len(nums) - 1
            while j < k:
                s = nums[i] + nums[j] + nums[k]
                if s == 0:
                    out.append([nums[i], nums[j], nums[k]])
                    j += 1
                    k -= 1
                    while j < k and nums[j] == nums[j-1]:
                        j += 1
                    while j < k and nums[k] == nums[k+1]:
                        k -= 1
                elif s < 0:
                    j += 1
                    while j < k and nums[j] == nums[j-1]:
                        j += 1
                else:
                    k -= 1
                    while j < k and nums[k] == nums[k+1]:
                        k -= 1
        return out

insert image description here

18. The sum of four numbers (medium)

insert image description here

V1 (refer to the solution of the sum of the three numbers in the above question)

First fix a, then fix d, and then convert the problem into the problem of the above question "sum of three numbers" after fixing both ends.

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        out = []
        nums.sort()
        for a in range(len(nums) - 3):
            for d in range(len(nums)-1, a+2, -1):
                b = a + 1
                c = d - 1
                while b < c:
                    s = nums[a] + nums[b] + nums[c] + nums[d]
                    if s == target:
                        m = [nums[a], nums[b], nums[c], nums[d]]
                        if m not in out:
                            out.append(m)
                        b += 1
                        c -= 1
                    elif s < target:
                        b += 1
                    else:
                        c -= 1
        return out

insert image description here

V2 (refine the search scope based on V1)

Four more lines of code have been added, and the execution time has been greatly reduced.

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        out = []
        nums.sort()
        for a in range(len(nums) - 3):
        	#### 缩小搜索范围
            if nums[a] + nums[a+1] + nums[a+2] + nums[a+3] > target:
                break
            ####
            for d in range(len(nums)-1, a+2, -1):
            	#### 缩小搜索范围
                if nums[a] + nums[d-2] + nums[d-1] + nums[d] < target:
                    break
                ####
                b = a + 1
                c = d - 1
                while b < c:
                    s = nums[a] + nums[b] + nums[c] + nums[d]
                    if s == target:
                        m = [nums[a], nums[b], nums[c], nums[d]]
                        if m not in out:
                            out.append(m)
                        b += 1
                        c -= 1
                    elif s < target:
                        b += 1
                    else:
                        c -= 1
        return out

insert image description here

454. Adding Four Numbers II

insert image description here

V1 (time limit exceeded)

Directly looping four times, it must exceed the time limit

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        count = 0
        nums1.sort()
        nums2.sort()
        nums3.sort()
        nums4.sort()
        if nums1[0] + nums2[0] + nums3[0] + nums4[0] > 0:
            return 0
        elif nums1[-1] + nums2[-1] + nums3[-1] + nums4[-1] < 0:
            return 0
        n = len(nums1)
        for i in range(n):
            if nums1[i] + nums2[0] + nums3[0] + nums4[0] > 0 or nums1[i] + nums2[-1] + nums3[-1] + nums4[-1] < 0:
                        continue
            for j in range(n):
                if nums1[i] + nums2[j] + nums3[0] + nums4[0] > 0 or nums1[i] + nums2[j] + nums3[-1] + nums4[-1] < 0:
                        continue
                for k in range(n):
                    if nums1[i] + nums2[j] + nums3[k] + nums4[0] > 0 or nums1[i] + nums2[j] + nums3[k] + nums4[-1] < 0:
                        continue
                    for l in range(n):
                        if nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0:
                            count += 1
        return count

V2 (out of time)

Tried to reduce the number of loops by only looping over unique values, but still time limit exceeded

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        import numpy as np
        count = 0
        nums1, nums1_count = np.unique(nums1, return_counts=True)
        nums2, nums2_count = np.unique(nums2, return_counts=True)
        nums3, nums3_count = np.unique(nums3, return_counts=True)
        nums4, nums4_count = np.unique(nums4, return_counts=True)
        if nums1[0] + nums2[0] + nums3[0] + nums4[0] > 0:
            return 0
        elif nums1[-1] + nums2[-1] + nums3[-1] + nums4[-1] < 0:
            return 0
        for i in range(len(nums1)):
            if nums1[i] + nums2[0] + nums3[0] + nums4[0] > 0 or nums1[i] + nums2[-1] + nums3[-1] + nums4[-1] < 0:
                continue
            for j in range(len(nums2)):
                if nums1[i] + nums2[j] + nums3[0] + nums4[0] > 0 or nums1[i] + nums2[j] + nums3[-1] + nums4[-1] < 0:
                    continue
                for k in range(len(nums3)):
                    if nums1[i] + nums2[j] + nums3[k] + nums4[0] > 0 or nums1[i] + nums2[j] + nums3[k] + nums4[-1] < 0:
                        continue
                    for l in range(len(nums4)):
                        if nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0:
                            count += nums1_count[i]*nums2_count[j]*nums3_count[k]*nums4_count[l]
        return int(count)

V3 (problem solution, transform the sum of four numbers into the sum of two numbers)

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hashmap = dict()
        count = 0
        for i in nums1:
            for j in nums2:
                hashmap[i+j] = hashmap.get(i+j, 0) + 1
        for k in nums3:
            for l in nums4:
                if -k-l in hashmap:
                    count += hashmap[-k-l]
        return count

insert image description here

V4(collections.Counter)

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        from collections import Counter
        dic = Counter(a+b for a in nums1 for b in nums2)
        return sum(dic.get(-c-d, 0) for c in nums3 for d in nums4)

作者:QQqun902025048
链接:https://leetcode-cn.com/problems/4sum-ii/solution/2-xing-python-by-qqqun902025048-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

insert image description here

summary

  • Use add to add elements to a collection, and append to add elements to a list.
  • Keep the loop as short as possible.
  • Narrow down the search range as much as possible by adding judgment conditions in the loop.
  • Judging the loop uses the fast and slow pointer.
  • Functions can be used to count all elements and their occurrences in a string (or other hashable object) collections.Counter().
  • It is more efficient to use multiplication instead of loop when you need to repeat a string.

Guess you like

Origin blog.csdn.net/zylooooooooong/article/details/119876058