Leetcode Hot 100 刷题记录,python语言
128 最长连续序列
参考https://leetcode.cn/problems/longest-consecutive-sequence/solutions/276931/zui-chang-lian-xu-xu-lie-by-leetcode-solution
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
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
while current_num + 1 in nums_set:
current_num += 1
current_streak += 1
longest_streak = max(longest_streak, current_streak)
return longest_streak
438 找到字符串中所有字母异位词
这段代码是用来解决 LeetCode 上的 “Find All Anagrams in a String” 问题,目的是找出字符串 s 中所有与字符串 p 是字母异位词的子串的起始索引。下面是对代码中各部分的解释:
变量说明:
s_len:字符串 s 的长度。
p_len:字符串 p 的长度。
ans:存放结果,即符合条件的起始索引。
s_count 和 p_count:分别是长度为 26 的数组,用来记录字符串中各个字符的出现次数。这里假设只考虑小写字母,因此数组长度为 26。s_count 记录当前窗口(或子串)中字符的出现次数,p_count 则记录模式串 p 中字符的出现次数。
初始化计数器:
遍历模式串 p 的前 p_len 个字符,更新 s_count 和 p_count。
s_count[ord(s[i]) - 97] += 1:将字符串 s 中当前字符的计数加一。ord(s[i]) - 97 的部分将字符映射到 s_count 数组的索引,即 ‘a’ 对应索引 0,‘b’ 对应索引 1,…,‘z’ 对应索引 25。
p_count[ord(p[i]) - 97] += 1:将模式串 p 中当前字符的计数加一。
初始比较:
如果初始时 s_count 等于 p_count,则说明从 s 的起始位置开始的长度为 p_len 的子串是 p 的字母异位词,将起始索引 0 加入 ans 中。
滑动窗口过程:
从索引 0 开始到 s_len - p_len 结束,依次滑动窗口。
每次滑动窗口时,更新 s_count:
s_count[ord(s[i]) - 97] -= 1:将窗口左边界字符在 s_count 中的计数减一。
s_count[ord(s[i + p_len]) - 97] += 1:将窗口右边界字符在 s_count 中的计数加一。
每次更新窗口后,比较 s_count 是否等于 p_count,如果相等,则将当前窗口的起始索引 i + 1 加入 ans 中。
返回结果:
返回 ans,其中存储了所有符合条件的起始索引。
这种方法的时间复杂度为 O(n),其中 n 是字符串 s 的长度。主要的计算量在于遍历字符串和更新计数器,而每次更新计数器都是常数时间操作。
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
s_len, p_len = len(s), len(p)
if s_len < p_len:
return []
ans = []
s_count = [0] * 26
p_count = [0] * 26
for i in range(p_len):
s_count[ord(s[i]) - 97] += 1 #ord('a') = 97, b 98, c 99
p_count[ord(p[i]) - 97] += 1
if s_count == p_count:
ans.append(0)
for i in range(s_len - p_len): # s_count还保留着初始窗口的字母统计次数;滑动窗口的左边界,循环;每滑动一次,只减去开头,增加结尾的字符,中间不动,所以,没有i到i+p_len中间的字符次数变化
s_count[ord(s[i]) - 97] -= 1
s_count[ord(s[i + p_len]) - 97] += 1 # 滑动窗口的右边界
if s_count == p_count:
ans.append(i + 1)
return ans
560 和为K的子数组
变量说明:
nums:输入的整数数组。
k:目标和。
count:符合条件的子数组个数,即和为 k 的连续子数组个数。
sum:当前累积的子数组和。
sumDict:字典,用来记录累积和出现的次数。键为累积和的值,值为该累积和出现的次数。初始时,将 {0: 1} 放入字典中,表示累积和为 0 的情况出现了 1 次。
解题思路:
初始化:
count 初始化为 0,用于计数符合条件的子数组个数。
sum 初始化为 0,用于累积当前子数组的和。
sumDict 初始化为 {0: 1},表示累积和为 0 的情况出现了 1 次。
遍历数组 nums:
每次遍历到数组中的一个数 num,将其加到 sum 中,表示当前累积的子数组和。
判断 sum - k 是否在 sumDict 中:
如果 sum - k 存在于 sumDict 中,说明之前有子数组的累积和为 sum - k,此时 sum - (sum - k) = k,即找到了一个符合条件的子数组,将 count 加上 sumDict[sum - k],表示有多少个以前累积和为 sum - k 的子数组,现在都可以形成一个新的符合条件的子数组。
更新 sumDict:
将 sum 加入 sumDict 中,如果 sum 已经在 sumDict 中,将其对应的值加 1;否则,将 sum 加入 sumDict,并将其值设为 1。
返回结果:
遍历完整个数组后,count 中存储的就是所有和为 k 的连续子数组的个数,将其作为结果返回。
时间复杂度分析:
该算法只需要遍历数组一次,每次操作都是常数时间复杂度,因此总体时间复杂度为 O(n),其中 n 是数组 nums 的长度。
空间复杂度主要取决于 sumDict 的大小,最坏情况下 sumDict 可能包含 n 个不同的累积和,因此空间复杂度为 O(n)。
这种方法利用了累积和的性质,通过哈希表记录累积和出现的次数,从而有效地解决了该问题。
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
if not nums:
return 0
count = 0 # 有多少个满足条件的连续子数组
sum = 0 # 当前累计的子数组的和
sumDict = {0: 1} # 哈希表 ;用来记录累积和出现的次数。
# 键为累积和的值,值为该累积和出现的次数。
# 初始时,将 {0: 1} 放入字典中,表示累积和为 0 的情况出现了 1 次。
for num in nums: # 比如以nums = [1,1,1], k = 2为例子,
#第一次循环sum=1,加入字典{1:1},
#第二次sum=2,sum-k=0,在字典中,count=0+1.同时sum=2加入字典,{2:1}
#第三次sum=3,sum-k=3-2=1在字典中{1:1},就是说,在前面某个位置到开头的累计和为1,那么从那个位置到当前num的累计和为sum - (sum-k) = k,为目标和k。所以count加上,那个位置对应的次数,比如有多个那个位置
sum += num # 当前子数组的和,累计
if sum - k in sumDict:
count += sumDict[sum - k]
if sum in sumDict:
sumDict[sum] += 1
else:
sumDict[sum] = 1
return count
238 除自身以外数组
这段代码是用来计算除自身以外数组元素的乘积的,使用了两个阶段的累积乘积计算方法,分别是下三角和上三角的概念。
让我们逐步解释这段代码:
初始化变量:
ans 是一个长度为 len(nums) 的列表,初始化为全1。它最终会存储每个元素左侧所有元素的乘积。
tmp 是一个临时变量,用于存储右侧所有元素的乘积的累积值,初始为1。
计算下三角(左侧乘积):
第一个 for 循环从 1 到 len(nums)-1,计算 ans[i],表示 nums[i] 左侧所有元素的乘积。具体计算为 ans[i] = ans[i - 1] * nums[i - 1]。
这个循环完成后,ans[i] 存储的是 nums[i] 左侧所有元素的乘积。
计算上三角(右侧乘积):
第二个 for 循环从 len(nums)-2 到 0,逆序计算每个元素 nums[i] 右侧所有元素的乘积。
在循环中,tmp 乘以 nums[i + 1],然后 ans[i] 乘以 tmp。这样可以得到 nums[i] 左侧和右侧所有元素的乘积。
这一步完成后,ans[i] 存储的是除 nums[i] 外所有元素的乘积。
返回结果:
最后返回 ans 列表,其中 ans[i] 存储的是除 nums[i] 外所有元素的乘积。
这种方法避免了使用除法操作,通过两个阶段的累积乘积计算来实现目标,时间复杂度为 O(n),空间复杂度为 O(1),符合题目要求。
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
res = [1]*len(nums)
tmp = 1
for i in range(1, len(nums)):
res[i] = res[i-1] * nums[i-1] # 下三角,存储每个元素左侧所有元素的乘积。
for i in range(len(nums)-2, -1, -1):
tmp *= nums[i+1] # 上三角,存储每个元素右侧所有元素的乘积。
res[i] *= tmp
return res