力扣hot100速通(7.9)|49.字母异位词分组 128.最长连续序列 283.移动零 11.盛最多水的容器 42.接雨水
49.字母异位词分组
直接看答案了,思路是用字典,排序后的字符串作为key,排序前的作为value,一步步加入就好了
class Solution:def groupAnagrams(self, strs: List[str]) -> List[List[str]]:result = dict()for word in strs:sorted_word = "".join(sorted(word)) #排序字符串之后获得是排序后的列表print(word)if sorted_word in result.keys():result[sorted_word].append(word)else:result[sorted_word]= [word]return list(result.values())
128.最长连续序列
居然说是hash法,让我思考一下,我可以直接暴力求解的,但是得排序,这样复杂度就是O(nlogn)的
class Solution:def longestConsecutive(self, nums: List[int]) -> int:if len(nums)<=1:return len(nums)result = 1tmp=1nums.sort()for i in range(1,len(nums)):if nums[i]==nums[i-1]+1:tmp+=1result = max(tmp,result)elif nums[i]==nums[i-1]:continueelse:tmp=1return result
题目要求我们给出O(n)的方法,需要好好斟酌一下,如何使用hash法降低复杂度,看了解析
这个问题要求时间复杂度为O(n),可以使用哈希表(字典)来实现。
1. 创建一个哈希表:
- 用来存储每个数对应的连续序列的长度。
2. 遍历数组:
- 对于每个数,如果它已经在哈希表中,直接跳过。
- 如果是新数:
- 检查这个数的左右相邻数是否在哈希表中,取出它们对应的连续序列长度 left 和 right。
- 计算当前数的连续序列长度:cur_length = left + right + 1。
- 更新最大长度 max_length。
- 更新当前数及其连续序列两端点的长度为 cur_length。
3. 返回最大长度:
- 在遍历结束后,即可得到最长的连续序列长度。
class Solution:def longestConsecutive(self, nums: List[int]) -> int:nums_dict = {}max_len =0for i in range(len(nums)):if nums[i] in nums_dict.keys():continueleft = nums_dict.get(nums[i]-1,0)right = nums_dict.get(nums[i]+1,0)cur_len = left+right+1max_len = max(max_len,cur_len)nums_dict[nums[i]] = cur_lennums_dict[nums[i]-left] = cur_lennums_dict[nums[i]+right]= cur_lenreturn max_len
这里注意,只需要修改两端的值,中间的值不会再用的到了,复杂度为O(n)
283.移动零
采用类似快排的划分思想,以非0数为基准,左边为非零数,右边为0,通过zeroindex
记录第一个为0的元素的下标。然后循环遍历nums数组,当nums[i]!=0
时,nums[i]
和nums[zeroindex]
进行交换,然后zeroindex++
时间复杂度:O(n),空间复杂度:O(1)
看了下是这样的,我们首先找到第一个为0 的位置,然后这个时候我们应当设置zeroindex为当前位置,i继续遍历,加入nums[i]!=0,那么我们就交换当前值和nums[zeroindex],然后同时让zeroindex+1,这样的话保证0被移动到后面去了,而这个为0的最后会被放到后面去
class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""if len(nums)<=1:return numszeroindex=-1for i in range(len(nums)):if nums[i]==0 and zeroindex==-1:zeroindex=iif nums[i]!=0 and zeroindex!=-1:nums[i],nums[zeroindex]=nums[zeroindex],nums[i]zeroindex+=1return nums
11.盛最多水的容器
看到这个题目我第一时间想到的是暴力搜索,理论上遍历所有容器的容量,找到最大值就好,但是我们仔细思考一下,不难发现,假设我们用left和right表示两个容器壁,那么容器的容量计算公式应当是
(right-left)*min(height[left],height[right])
由于知道是双指针解法,因此我初步判断,我们每次动的指针应当是矮的那一根,然后直到,两指针相遇为止,因为我们动高的那一根,无论怎么动,都不会使得容器容积变大了,因此我们就明白了应该如何减少遍历次数
class Solution:def maxArea(self, height: List[int]) -> int:left,right = 0,len(height)-1max_volum=0while left<right:max_volum = max(max_volum,(right-left)*min(height[left],height[right]))if height[left]<=height[right]:left+=1else:right-=1return max_volum
42.接雨水
思考了一下,没想明白如何计算储水量,看下解析,我看到的一个比较好的双指针解法是这样的,我们首先找到最高的柱子的位置,记住这个位置,然后slow从左侧开始遍历,right一开始设置为slow+1,如果说right比slow高了,我们就要更新柱子,并计算这两个之间的储水值
class Solution:def trap(self, height: List[int]) -> int:total = 0left,right=0,len(height)-1maxl,maxr=0,0while left<=right:if height[left]>=maxl:maxl=height[left]if height[right]>=maxr:maxr=height[right] if height[left]<=height[right]:total+=maxl-height[left]left+=1else:total+=maxr-height[right]right-=1return total