2021-08-15 数组:其他小题

38 阅读2分钟

2021-08-15 数组:其他小题

除自身以外数组的乘积

  • 挖掘几点信息:

    • 除自身以外:即左边乘积*右边乘积
    • 乘积:累乘,可以利用先前结果(用两个变量维护)
    • 记录:直接使用答案数组记录,左至右左边乘积,反之亦然,然后乘以变量即为累积的另一边的成绩。故而至少需要两个数组,无法进行原地覆盖。
class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        n = len(nums)
        ans = [1]*n
        per, suf = 1, 1
        for i in range(n):
            ans[i] = ans[i] * per
            ans[n-i-1] = ans[n-i-1] * suf
            per = per * nums[i]
            suf = suf * nums[n-i-1]
        return ans

打乱数组

  • 暴力法,但要注意赋值操作实际上是对象的引用(浅拷贝),所以需要额外空间记录原数组:
class Solution:
    def __init__(self, nums):
        self.array = nums
        # 开辟新空间
        self.original = list(nums)

    def reset(self):
        self.array = self.original
        self.original = list(self.original)
        return self.array

    def shuffle(self):
        aux = list(self.array)

        for idx in range(len(self.array)):
            remove_idx = random.randrange(len(aux))
            self.array[idx] = aux.pop(remove_idx)

        return self.array
  • Fisher-Yates 洗牌算法:在每次迭代中,生成一个范围在当前下标到数组末尾元素下标之间的随机整数。接下来,将当前元素和随机选出的下标所指的元素互相交换。注意,当前元素是可以和它本身互相交换的。
class Solution:
    def __init__(self, nums):
        self.array = nums
        self.original = list(nums)

    def reset(self):
        self.array = self.original
        self.original = list(self.original)
        return self.array

    def shuffle(self):
        for i in range(len(self.array)):
            swap_idx = random.randrange(i, len(self.array))
            self.array[i], self.array[swap_idx] = self.array[swap_idx], self.array[i]
        return self.array

两个数组的交集Ⅱ

  • 排序+双指针
class Solution:
    def intersect(self, nums1: [int], nums2: [int]) -> [int]:
        nums1.sort()
        nums2.sort()
        r = []
        left, right = 0, 0
        while left < len(nums1) and right < len(nums2):
            if nums1[left] < nums2[right]:
                left += 1
            elif nums1[left] == nums2[right]:
                r.append(nums1[left])
                left += 1
                right += 1    
            else:
                right += 1
        return r
  • 哈希计数:

    • 两个数组分别维护自己的哈希表(相当于利用collections.Counter()
    class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return [*(collections.Counter(nums1) &
        		collections.Counter(nums2)).elements()]
        ```
    - 维护单个哈希表,利用计数判断
    ```python
    class Solution:
        def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        	# 节省空间,遍历较短数组
            if len(nums1) > len(nums2):
                return self.intersect(nums2, nums1)
            
            m = collections.Counter()
            for num in nums1:
                m[num] += 1
            
            intersection = list()
            for num in nums2:
                if (count := m.get(num, 0)) > 0:
                    intersection.append(num)
                    m[num] -= 1
                    if m[num] == 0:
                        m.pop(num)
            
            return intersection
    
  • 进阶3问:这个题解