秋招 hot100 刷题记录【1】

1.字母异位词分组
  • 思路:字母异位词 排序后是相同的
    • 排序后的字符串当作key
    • value初始化为列表 且每次添加的是字符串
  • 代码链接
  • collections.defaultdict(list)
class Solution(object):
    def groupAnagrams(self, strs):
        """
        :type strs: List[str]
        :rtype: List[List[str]]
        """
        # 创建一个字典,且value默认是列表型
        res = collections.defaultdict(list)
        
        for st in strs:
            key = "".join(sorted(st))
            res[key].append(st)
        
        return res.values()

2.最长连续序列
  • 思路:去重集合,找的是nums[i-1]是否在集合中,如果在跳过,否则此时的元素就是该序列的开头,然后依次判断nums[i+1]是否在集合中,再则++
  • 代码链接
class Solution(object):
    def longestConsecutive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 时间复杂度 O(n) 因为每个元素只进内层循环1次
        longest_streak = 0
        nums_set = set(nums) # 对列表进行去重
        
        for num in nums_set:

            if num - 1 not in nums_set:
                current_num = num
                current_streak = 1
            else:
                continue # 不加就无法通过
            while current_num + 1 in nums_set:
                current_num = current_num + 1
                current_streak = current_streak + 1

            longest_streak = max(longest_streak, current_streak)

        return longest_streak


3.移动零
  • 双指针,用一个指针i遍历数组,一个指针j来指代非零的index,如果nums[i]不是0,则交换nums[i]和nums[j],这样做相当于确保j指代0的位置,因为nums[i] = 0 的时候,j不移动,只有在i非0的时候才动,这样j会指向可以交换的位置
  • 代码链接

class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        if len(nums) == 1:
            return nums
        
        j = 0

        for i in range(0,len(nums)):
            if nums[i] != 0 :
                nums[i],nums[j] = nums[j],nums[i]
                j += 1
        return nums

4.承最多水的容器
  • 思路:明白体积公式 s = min(h[i],h[j]) *(j-i)
  • 双指针,初始化一个在0,一个在末尾,处于一个宽最大的地方,然后比较两边高度,只保留高较大的,另一边向内缩小,面积才可能变大,反之,一定会变小。
  • 代码链接
class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        # 时间复杂度o(n) 只遍历了一遍height
        i, j, res = 0, len(height)-1, 0
        # 面积计算公式 min(height[i],height[j]) * (j-i)
        while i < j:
            if height[i] < height[j]:
                res = max(res, height[i] * (j-i))
                i += 1
            else:
                res = max(res, height[j] * (j-i))
                j -= 1
        return res


5.三数之和
class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        # 时间复杂度 O(N^2):其中固定指针k循环复杂度 O(N),双指针 i,j 复杂度 O(N)。
        # 空间复杂度 O(1):指针使用常数大小的额外空间。
        nums.sort()
        res, k = [], 0
        for k in range(len(nums)-2):
            if nums[k] > 0:
                break # 最大的都大于0 其余的不可能大于0
            if k > 0 and nums[k] == nums[k-1]: 
                # print(k,nums[k],nums[k-1])
                continue # 去重问题
            i, j = k+1, len(nums) - 1
            while i < j:
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    i += 1
                    while i < j and nums[i] == nums[i - 1]:
                        i += 1 # 防止nums[i]重复
                    
                elif s > 0:
                    j -= 1
                    while i < j and nums[j + 1] == nums[j]:
                        j -= 1 # 防止nums[j]重复

                else:
                    res.append([nums[k],nums[i],nums[j]])
                    i += 1
                    j -= 1
                    while i < j and nums[i] == nums[i-1]:
                        i += 1 # 防止nums[j]重复
                    while i < j and nums[j+1] == nums[j]:
                        j -= 1 # 防止nums[j]重复
        return res

二刷

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        # 时间复杂度 O(N^2):其中固定指针k循环复杂度 O(N),双指针 i,j 复杂度 O(N)。
        # 空间复杂度 O(1):指针使用常数大小的额外空间。
        
        nums.sort()
        res =[]

        #  三数之和 因此只要遍历到倒数第3个位置
        for i in range(0,len(nums)-2):
            if nums[i] > 0:
                break # nums[i]是最小的因此如果大于0,没有可能其他的大于0
            if i > 0 and nums[i] == nums[i-1]:
                continue # 避免i出现重复
            j = i + 1
            k = len(nums)-1
            while j < k:
                s = nums[i] + nums[j] +nums[k]
                if s > 0:
                    k -= 1
                    while j < k and nums[k] == nums[k+1]: # 只要判断相邻的 而不是在while中写if 否则会超时
                             k -= 1
                elif s < 0:
                    j += 1
                    while j < k and nums[j] == nums[j-1]:
                            j += 1
                else:
                    res.append([nums[i], nums[j], nums[k]])
                    j += 1
                    k -= 1
                    while j < k and nums[k] == nums[k+1]:
                            k -= 1
                    while j < k and nums[j] == nums[j-1]:
                            j += 1
        return res
                            
            

6.接雨水
class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        # 时间复杂度o(n)
        # 空间复杂度o(n)

        # 每个位置想象为一个桶,而接水的高度 取决于桶两边的高度
        # (右边的高度取决于右边所有模板的最大高度
        # 左边的高度取决于左边所有模版的最大高度)
        # 整个水桶所装的水则 min(桶左右边的高度) - h
        n = len(height)
        pre_max = [0] * n #前缀最大值
        pre_max[0] = height[0]
        for i in range(1,n):
            pre_max[i] = max(pre_max[i-1], height[i])
        
        suf_max = [0] * n # 后缀最大值
        suf_max[-1] = height[-1]
        for i in range(n-2, -1, -1):
            suf_max[i] = max(suf_max[i+1], height[i])

        ans = 0
        for h, pre, suf in zip(height, pre_max, suf_max):
            ans += min(pre, suf) - h
        return ans


7.无重复字符串的最长子串
class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        # 时间复杂度 o(n)
        # 空间复杂度 哈希表最多存储为ASCII码 o(128) = o(1)
        if len(s) <= 1:
            return len(s) # 注意特殊值
        res = 0
        dic, i, j = {}, -1, 0
        for j,c in enumerate(s):
            if c in dic:
               i = max(i, dic[c]) # 此时更新左端点只要从上一次出现的位置开始即可 
            dic[c] = j # 哈希表记录
            res = max(res, j - i) # 更新结果为窗口长度,注意第一个j = 0,因此窗口的起始值应该是-1

        return res
8.找到字符串中所有的字母异位词
class Solution(object):
    def findAnagrams(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: List[int]
        """
        # 时间复杂度 o(m+(n−m)×Σ)
        # 空间复杂度 o(Σ)
        # 从s中找到所有p的异位词,返回的是所有p子串的起始索引
        s_len, p_len = len(s), len(p) # 获取两个字符串的长度
        if s_len < p_len:
            return [] # 如果s比p短,就不可能存在p的异位词
        
        ans = []
        s_count = [0] * 26
        p_count = [0] * 26

        # 1.维护窗口大小为p的滑动窗口 2.统计p中字符串情况
        for i in range(p_len):
            s_count[ord(s[i]) - 97] += 1
            p_count[ord(p[i]) - 97] += 1 # 计算每个字符出现的次数

        if s_count == p_count:
            ans.append(0) # 说明s的前p个字符就符合要求了
        
        for i in range(s_len - p_len):
            # 模拟窗口滑动
            s_count[ord(s[i]) - 97] -= 1
            s_count[ord(s[i + p_len]) - 97] += 1
            
            # 注意如果满足的时候 窗口的起始索引为 i + 1
            if s_count == p_count:
                ans.append(i + 1) #添加索引

        return ans 
            

9.和为k的子数组
class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        """
        给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
        子数组是数组中元素的连续非空序列。
        """
        # 思路:想到前缀和 对于数组任何位置j,前缀和 pre[j]指代的是0到j所有元素的总和
        # 因此 i+1到j的和 = pre[j] - pre[i]
        # k = pre[j] - pre[i],pre[j] = pre[i] + k

        ans = 0
        # 存储的是 key是前缀和 value是次数
        pre_sum = collections.defaultdict(int)

        pre_sum[0] = 1 # 和为0出现的次数 空集也是子集
        prefixsum = 0
        for i in range(len(nums)):
            prefixsum += nums[i]
            ans += pre_sum[prefixsum - k]
            pre_sum[prefixsum] += 1
        return ans


10.滑动窗口最大值
class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        """
        给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
        返回 滑动窗口中的最大值 。
        """
        # 滑动窗口 考虑双端队列
        if not nums or k == 0:
            return []
        deque = collections.deque()

        for i in range(k):
            # 形成队列 注意其中这个队列是递减的 然后我们每次要维持队首的数据是最大的
            while deque and deque[-1] < nums[i]:
                deque.pop()
            deque.append(nums[i])
        res = [deque[0]] # 别忘了第一个元素
        for i in range(k, len(nums)):
            # 如果此时要删除的元素刚好是滑动队列中最大的,则需要手动踢出队列pop 否则该元素已经在下一步被pop掉了
            if deque[0] == nums[i - k]:
                deque.popleft()
            # 把所有比当前要加入的元素小的在队列中都剔除,以便于窗口移动
            while deque and deque[-1] < nums[i]:
                deque.pop()
            deque.append(nums[i])
            res.append(deque[0])
        return res

11.最小覆盖子串
class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """

        if len(s) < len(t):
            return ""

        need = collections.defaultdict(int)

        for i in range(len(t)):
            need[t[i]] += 1
        needCnt = len(t) # 所需要的最少的字母数量
        left = 0
        res = (0, float("inf")) # 初始化结果
        # print(need)
        for i in range(len(s)):
            if need[s[i]] > 0: # 判断该字母是否有 因为初始化是0
                needCnt -= 1 # 如果是所需要的 就数量减1
            # 凑齐了字符串
            need[s[i]] -= 1
            if needCnt == 0:
                while True :
                    #print(i,left,need[s[left]],res)
                    c = s[left]
                    #print(c,need[c])
                    if need[c] == 0: # 如果这个字母是必须的 那么count >= 0
                        break # 不可缺少这个字母
                    need[c] += 1
                    left += 1 # 字符串开头开始向右移动 两步操作 1是need这个hash表变化 2是index移动
                    # 直到找到符合的最小子串就会break
                # 存储结果
                if (i - left) < (res[1] - res[0]):
                    res = (left, i)
                # 找到窗口后 寻找下一个窗口
                need[s[left]] += 1 # 注意这里要复原的是s[left] left要往内移动
                left += 1
                needCnt += 1

        return "" if res[1] > len(s) else s[res[0] : res[1] + 1]


        # # need 作用存储此时窗口中的字母为了达到 target中 所差的个数
        # need = collections.defaultdict(int) # 创建一个字典 并且在默认值上为0
        # # 构建need 用t 初始化need
        # for c in t:
        #     need[c] += 1
        # needCnt = len(t) # 所需要的字母总数量
        # i = 0
        # res = (0, float("inf")) # 初始化区间的值
        # # enumerate 指的迭代器 j是index c是s中的字母
        # for j,c in enumerate(s):
        #     # 判读 c 是否是 t 中必要的元素
        #     if need[c] > 0:
        #         needCnt -= 1 # 所需的字母数减1
        #     need[c] -= 1
        #     # 1.增加j直到当前窗口中包含了所有必须的字母
        #     if needCnt == 0:
        #         while True:
        #             c = s[i]
        #             if need[c] == 0: # 2.增加i知道找到t中所需的字母(所需的字母=0 多余<0)
        #                 break
        #             need[c] += 1
        #             i += 1
        #         if j - i < res[1] - res[0]:
        #             res = (i,j)
        #         need[s[i]] += 1 # 3.在找到这样的窗口之后 需要增加i找下一个窗口
        #         i += 1
        #         needCnt += 1
        # # 如果res从未被更新 则是空 否则根据下标获得子串
        # return "" if res[1] > len(s) else s[res[0] : res[1]+1]



12.最大子数组和
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 动态规划
        # dp[i] 包含nums[i]的最大连续字数组合
        if len(nums) == 1:
            return nums[0]
        dp = [0] * len(nums)
        dp[0] = nums[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i-1] + nums[i], nums[i]) # 要么包括该nums[i]组成 要么重新开始
            print(dp)
        return max(dp)

13.合并区间
class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        # 时间复杂度 o(nlogn)
        # 空间复杂度 o(logn) _ 排序需要的区间
        intervals.sort(key = lambda x:x[0]) # 以左端点开始排序
        res = []
        start = intervals[0][0]
        end = intervals[0][1]
        for i in range(1, len(intervals)):
            # print(i,j)
            if intervals[i][0] <= end: # 注意比较的是下一个区间头是否在其中
                # start = min(start, intervals[i][0])
                end = max(end, intervals[i][1])
            else:
                res.append([start, end])
                start = intervals[i][0]
                end = intervals[i][1]
        res.append([start, end]) # 注意其中最后一次的区间要放进去
        return res
            



14.轮转数组
class Solution(object):
    def rotate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: None Do not return anything, modify nums in-place instead.
        """


        # 轮转数组k次 时间复杂度 o(n) 空间复杂度 o(1)
        # 注意点 1 轮转k 相当于转 k mod n
        # 2. 轮转数组相当于 先整体翻转 接着翻转前k个,再反转后面 n-k 个

        k = k % len(nums)
        self.reverse(nums, 0, len(nums)-1)
        self.reverse(nums, 0, k - 1)
        self.reverse(nums, k, len(nums)-1)
        

    def reverse(self, s, left, right):
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1


15.除自身以外的乘积
class Solution(object):
    def productExceptSelf(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        """
        原数组:       [1       2       3       4]
        左部分的乘积:   1       1      1*2    1*2*3
        右部分的乘积: 2*3*4    3*4      4      1
        结果:        1*2*3*4  1*3*4   1*2*4  1*2*3*1
        """
        # 例【1,2,3,4】
        # 注意求的是乘积 因此初始化是1开始的
        ans = [1] * len(nums)
        for i in range(1, len(nums)): # 【1,1,1*2,1*2*3】
            ans[i] = ans[i-1] * nums[i-1] # 计算的是上面行的乘积
        print(ans)
        tmp = 1
        # 右边区域值是从右到左变小的 因此是要倒序
        # tmp 应该是 【 1,4,3*4,2*3*4】
        for j in range(len(nums) - 2, -1, -1):
            tmp *= nums[j+1]
            ans[j] *= tmp 
        return ans
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值