LeetCode 热题 100

未完待续…

一、哈希

1、两数之和

在这里插入图片描述

# 暴力解,时间复杂度:o(n^2)
class Solution(object):def twoSum(self, nums, target):""":type nums: List[int]:type target: int:rtype: List[int]"""for i in range(len(nums)):for j in range(i + 1, len(nums)):if nums[j] == target - nums[i]:print([i, j])return [i, j]# print(i, j)# 哈希优化解,时间复杂度o(n)
class Solution2(object):def twoSum(self, nums, target):dic = {}for i in range(len(nums)):tar_num = target - nums[i]if tar_num in dic:print([dic[tar_num], i])return [dic[tar_num], i]dic[nums[i]] = ireturn []if __name__ == '__main__':# s = Solution()# # s.twoSum([2, 7, 11, 15], 9)# # s.twoSum([3, 2, 4], 6)# s.twoSum([3, 3], 6)s = Solution2()# s.twoSum([2, 7, 11, 15], 9)s.twoSum([3, 2, 4], 6)# s.twoSum([3, 3], 6)

2.字母异位词分组

在这里插入图片描述

# 自己写的
class Solution(object):def groupAnagrams(self, strs):""":type strs: List[str]:rtype: List[List[str]]"""dic = {}final_list = []for word in strs:sort_tup_word = tuple(list(sorted(word)))if sort_tup_word in dic:dic[sort_tup_word].append(word)else:dic[sort_tup_word] = [word]  # value为列表,才可以实现appendprint(dic)for k in dic:final_list.append(dic.get(k))print(final_list)return final_list# 看了大佬之后的优化方法,思路倒是一样的,只是对代码没那么熟悉
class Solution2(object):def groupAnagrams(self, strs):""":type strs: List[str]:rtype: List[List[str]]"""dic = {}final_list = []for word in strs:sort_word = "".join(sorted(word))if sort_word in dic:dic[sort_word].append(word)else:dic[sort_word] = [word]print(list(dic.values()))return list(dic.values())if __name__ == '__main__':# strs = ["eat", "tea", "tan", "ate", "nat", "bat"]# # strs = [""]# # strs = ["a"]# # for i in strs:# #     print(list(sorted(i)))# s = Solution()# s.groupAnagrams(strs)strs = ["eat", "tea", "tan", "ate", "nat", "bat"]# strs = [""]# strs = ["a"]# for i in strs:#     print(list(sorted(i)))s = Solution2()s.groupAnagrams(strs)

3.最长连续序列

在这里插入图片描述

class Solution(object):def longestConsecutive(self, nums):""":type nums: List[int]:rtype: int"""sort_num = sorted(set(nums)) # 题目没有明说,当出现两个数字相同时,要去重!cnt = 0 if len(nums) == 0 else 1 # 避免输入一个空列表的情况cnt_list = []for i in range(len(sort_num)):if i+1 < len(sort_num):if sort_num[i] + 1 == sort_num[i+1]:cnt += 1else:cnt_list.append(cnt)cnt = 1cnt_list.append(cnt)print(max(cnt_list))return max(cnt_list)if __name__ == '__main__':# nums = [100, 4, 200, 1, 3, 2]# nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]# nums = [9, 1, 4, 7, 3, -1, 0, 5, 8, -1, 6]nums = [1, 2, 0, 1]s = Solution()s.longestConsecutive(nums)

二:双指针

4、移动零

在这里插入图片描述

# 实际开发写法,类似快排的实现
class Solution1(object):def moveZeroes(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""zero_index = 0for i in range(len(nums)):if nums[i] != 0:tmp = nums[zero_index]nums[zero_index] = nums[i]nums[i] = tmpzero_index += 1  # 一定要index所在值非0了,再往后移动,否则会导致数据0排在非0前面return nums# 缩写写法
class Solution2(object):def moveZeroes(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""zero_index = 0for i in range(len(nums)):if nums[i] != 0:nums[zero_index], nums[i] = nums[i], nums[zero_index]zero_index += 1return numsif __name__ == '__main__':nums = [0, 1, 0, 3, 12]# nums = [0]# nums = [0, 0, 1]s = Solution2()print(s.moveZeroes(nums))

5、盛水最多的容器

在这里插入图片描述

class Solution(object):def maxArea(self, height):  # 这个会超出时间限制""":type height: List[int]:rtype: int"""max_area = 0for i in range(len(height) - 1):for j in range(i+1, len(height)):length = j - iwidth = min(height[i], height[j])if max_area < length*width:max_area = length*widthprint(max_area)return max_area# 双指针,从两头开始内卷,先卷了挫的那头def maxArea_2(self, height):""":type height: List[int]:rtype: int"""l = 0r = len(height) - 1max_area = 0while l < r:tmp = min(height[l], height[r]) * (r-l)max_area = max(max_area, tmp)if height[l] < height[r]:l += 1else:r -= 1print(max_area)return max_areaif __name__ == '__main__':# test_list = [1, 8, 6, 2, 5, 4, 8, 3, 7]test_list = [1, 1]s = Solution()# s.maxArea(test_list)s.maxArea_2(test_list)

6、三数之和

在这里插入图片描述

本题的暴力题解可以仿照二数之和,直接三层遍历,取和为 0 的三元组,并记录下来,最后再去重。但是作为一个有智慧的人,我们不能这么去做。
因为我们的目标是找数,当然使用指针的方式最简单。假若我们的数组为:

[-1, 0, 1, 2, -1, -4]
求解过程如下:首先我们先把数组排个序(原因一会儿说),排完序长这样:
在这里插入图片描述
因为我们要同时找三个数,所以采取固定一个数,同时用双指针来查找另外两个数的方式。所以初始化时,我们选择固定第一个元素(当然,这一轮走完了,这个蓝框框我们就要也往前移动),同时将下一个元素和末尾元素分别设上 left 和 right 指针。画出图来就是下面这个样子:
在这里插入图片描述
现在已经找到了三个数,当然是计算其三值是否满足三元组。但是这里因为我们已经排好了序,如果**固定下来的数(上面蓝色框框)本身就大于 0,那三数之和必然无法等于 0 **。比如下面这种:
在这里插入图片描述

然后自然用脚指头也能想到,我们需要移动指针。现在我们的排序就发挥出用处了,如果和大于 0,那就说明 right 的值太大,需要左移。如果和小于 0,那就说明 left 的值太小,需要右移。(上面这个思考过程是本题的核心) 整个过程如下图所示:
在这里插入图片描述
其中:在第 6 行时,因为三数之和大于 0,所以 right 进行了左移。最后一行,跳过了重复的 -1。

然后啰嗦一句,因为我们需要处理重复值的情况。除了固定下来的i值(蓝框框),left 和 right 当然也是需要处理重复的情况,所以对于 left 和 left+1,以及 right 和 right-1,我们都单独做一下重复值的处理。(其实没啥处理,就是简单的跳过)

class Solution(object):def threeSum(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""n = len(nums)res = []if not nums or n < 3:return []nums.sort()  # 排序是为了使用双指针,从最小的数字开始遍历res = []for i in range(n):if nums[i] > 0:  # 如果排序之后数据i是大于0的值,那么就没必要进行循环了return resif i > 0 and nums[i] == nums[i - 1]:  # 跳过重复的数据continueL = i + 1  # 初始化R = n - 1  # 初始化while L < R:if nums[i] + nums[L] + nums[R] == 0:res.append([nums[i], nums[L], nums[R]])while L < R and nums[L] == nums[L + 1]:  # 跳过重复的数字L = L + 1while L < R and nums[R] == nums[R - 1]:R = R - 1L = L + 1  # 盲猜为了得到L>R,结束循环R = R - 1  # 盲盲猜为了得到L>R,结束循环elif nums[i] + nums[L] + nums[R] > 0:R = R - 1else:L = L + 1return resif __name__ == '__main__':nums = [-1, 0, 1, 2, -1, -4]s = Solution()print(s.threeSum(nums))

7、接雨水

在这里插入图片描述
暴力解:很明显每个柱子顶部可以储水的高度为,该柱子的左右两侧最大高度的较小者减去此柱子的高度。因此我们只需要遍历每个柱子,累加每个柱子可以储水的高度即可。
双指针:
在这里插入图片描述


class Solution(object):    # 暴力解,时间会超时  o(n^2)def trap(self, height):# 很明显每个柱子顶部可以储水的高度为:该柱子的左右两侧最大高度的较小者减去此柱子的高度。# 因此我们只需要遍历每个柱子,累加每个柱子可以储水的高度即可。""":type height: List[int]:rtype: int"""nums = 0for i in range(1, len(height) - 1):max_l = 0max_r = 0for j in range(0, i):max_l = max(height[j], max_l)for j in range(i + 1, len(height)):max_r = max(height[j], max_r)tmp = min(max_r, max_l) - height[i]if tmp < 0:tmp = 0nums += tmpreturn numsdef trap_2(self, height):  # 双指针解,有点无法解释...# 1、初始左右指针在数组的第一个位置和最后一个位置# 2、如果左指针所指柱子的高度小于右指针所指柱子的高度,那么左右指针之间柱子的接雨水量取决于左指针所指柱子的高度,从左向右移动左指针,# 并记录柱子高度的最大值,如果当前柱子高度小于最大值,则当前柱子可以接雨水为柱子高度的最大值减去当前柱子高度# 3、否则,如果右指针所指柱子的高度小于左指针所指柱子的高度,那么左右指针之间柱子的接雨水量取决于右指针所指柱子的高度# 从右向左移动右指针,并记录柱子高度的最大值# 如果当前柱子高度小于最大值,则当前柱子可以接雨水为柱子高度的最大值减去当前柱子高度# 4.重复步骤2, 3""":type height: List[int]:rtype: int"""ans = 0left, right = 0, len(height) - 1leftMax = rightMax = 0while left < right:leftMax = max(leftMax, height[left])rightMax = max(rightMax, height[right])if height[left] < height[right]:ans += leftMax - height[left]left += 1else:ans += rightMax - height[right]right -= 1return ansif __name__ == '__main__':height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]s = Solution()# print(s.trap(height))print(s.trap_2(height))

三、滑动窗口

8、无重复字符的最长子串

在这里插入图片描述
在这里插入图片描述

class Solution(object):def lengthOfLongestSubstring(self, s):""":type s: str:rtype: int"""if len(s) == 0:return 0if len(s) == 1:return 1data_list = list(s)result = []for i in range(len(data_list) - 1):tmp = data_list[i]for dst in range(i, len(data_list) - 1):if data_list[dst + 1] in tmp:result.append(set(tmp))breakelse:tmp += data_list[dst+1]if dst + 1 == len(data_list) - 1:result.append(set(tmp))return len(max(result, key=len))if __name__ == '__main__':data = "abcabcbb"# data = "bbbbb"# data = "pwwkew"# data = " "# data = "au"# data = "cdd"# data = "abcabcbb"s = Solution()print(s.lengthOfLongestSubstring(data))

9、找出字符串中所有字母异位词

在这里插入图片描述
逻辑:遍历s字符串中,当窗口大小与P_len一样时,比较两个窗口的字母出现的次数,相同即保留相应的下标;
假设示例:
在这里插入图片描述
循环遍历s字符串,i经过两轮循环,窗口往右走,窗口扩大一次,相应schar的字母次数值就要+1,当窗口长度扩大至2(i=1),此时scharpchar,保留i - p_len + 1 (+1是因为i是从0开始) = 0的下标;
在这里插入图片描述
继续遍历,i=2,此时i>=p_len,超出p的长度了,要减去第一个进入窗口的字母次数值,schar={‘a’:1,‘b’:1},此时schar
pchar,保留i - p_len + 1 (+1是因为i是从0开始) = 1的下标;
在这里插入图片描述
继续遍历,i=3,重复第三张图操作,b值减1,b变为0,要从计数中删除;
此时schar==pchar,保留i - p_len + 1 (+1是因为i是从0开始) = 2的下标;
在这里插入图片描述

继续遍历,i=4,重复第三张图操作,a值减1,a变为0,要从计数中删除;
此时schar != pchar,不保留下标,遍历结束;
在这里插入图片描述
最终结果:[0, 1, 2]

class Solution(object):  --排序暴力检索,会超时def findAnagrams(self, s, p):""":type s: str:type p: str:rtype: List[int]"""len_tar = len(p)target = sorted(p)result = []for i in range(len(s) - len_tar + 1):if target == sorted(s[i:i + len_tar]):result.append(i)return resultclass Solution:def findAnagrams(self, s, p):  -- 统计窗口出现次数实现方案,可实现""":type s: str:type p: str:rtype: List[int]"""from collections import Counters_len, p_len = len(s), len(p)pChar, sChar = Counter(p), Counter()result = []for i in range(s_len):sChar[s[i]] += 1if i >= p_len:sChar[s[i - p_len]] -= 1if sChar[s[i - p_len]] == 0:del sChar[s[i - p_len]]if pChar == sChar:result.append(i - p_len + 1)return resultif __name__ == '__main__':# s = "cbaebabacd"# p = "abc"s = "abab"p = "ab"# s = "abacbabc"# p = "abc"so = Solution()print(so.findAnagrams(s, p))  

四、子串

太难了,不会做

五、普通数组

1、最大子数组和(中等,人生哲理题)

在这里插入图片描述

# 该题双循环不用看了,必超时
# 核心是从前往后遍历,例如-2和1的sum,与1相比,1比-1大,pre就取1,依次与后一位数字比较
# 人生哲理是这行:pre = max(data, pre + data):后面的人与前一个max的人在一起,如果能变优秀,那么我就和它在一起过余生,否则还不如后面的人自己过日子;
class Solution(object):def maxSubArray(self, nums):""":type nums: List[int]:rtype: int"""pre = 0max_sum = nums[0]for data in nums:pre = max(data, pre + data)max_sum = max(pre, max_sum)return max_sumif __name__ == '__main__':so = Solution()nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]# nums = [-2, 1]print(so.maxSubArray(nums))

2、合并区间(中等)

在这里插入图片描述

class Solution:def merge(self, intervals):if len(intervals) == 0:return []res = []intervals.sort(key=lambda x: x[0])  # 先按区间左边界值由小到大排序for inter in intervals:if len(res) == 0 or res[-1][1] < inter[0]:  # 如果结果集最后一个元素的右边界比新加入区间的左边界小,直接加入结果集res.append(inter)else:  # 否则,说明新加入的和结果集最后一个区间有重合,更新区间右边界即可res[-1][1] = max(res[-1][1], inter[1])return resif __name__ == '__main__':so = Solution()intervals = [[6, 20], [1, 3], [2, 6], [5, 10], [15, 18]]print(so.merge(intervals))

3、轮转数组

在这里插入图片描述

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求余是因为k可能会大于数组的长度,直接旋转会导致数组元素重叠。通过取模运算可以确保k不会超过数组的长度,从而避免数组元素重叠的问题。k = k % len(nums)# 为什么不从k开始取,因为nums下标是从0开始的,k的值余下标实际是差1的,不利于定位# 而用负下标,-1代表就是最后一个元素,符合k的数值定义# 以后尽量都用负下表定位会简单很多nums[:] = nums[-k:] + nums[:-k]return numsif __name__ == '__main__':nums = [1, 2, 3, 4, 5, 6, 7]k = 6# nums = [-1, -100, 3, 99]# k = 2# nums = [1, 2]# k = 1# k = 2# k = 3so = Solution()print(so.rotate(nums, k))

除自身以外数组的乘积

在这里插入图片描述
分别使用pre和last两个列表存储每个位置对应的前缀乘积和后缀乘积;
之后相乘即可,直接两个for循环会超时;

class Solution(object):def productExceptSelf(self, nums):""":type nums: List[int]:rtype: List[int]"""answer = []# 前缀乘积pre = [1]tmp_pre = 1for i in range(len(nums) - 1):tmp_pre = tmp_pre * nums[i]pre.append(tmp_pre)# 后缀乘积last = [1]tmp_last = 1for i in range(len(nums) - 1):tmp_last = tmp_last * nums[len(nums) - i - 1]last.append(tmp_last)# 相乘for i in range(len(nums)):answer.append(pre[i] * last[len(nums) - i - 1])return answerif __name__ == '__main__':so = Solution()# nums = [1, 2, 3, 4]nums = [-1,1,0,-3,3]print(so.productExceptSelf(nums))

六、二叉树

1、中序遍历:

在这里插入图片描述

class Solution(object):def inorderTraversal(self, root):""":type root: TreeNode:rtype: List[int]"""res = []def dfs(root):if not root:return# 按照 左-打印-右的方式遍历dfs(root.left)res.append(root.val)dfs(root.right)dfs(root)return res
class Solution(object):def inorderTraversal(self, root):"""莫里斯遍历"""res = []pre = Nonewhile root:# 如果左节点不为空,就将当前节点连带右子树全部挂到# 左节点的最右子树下面if root.left:pre = root.leftwhile pre.right:pre = pre.rightpre.right = root# 将root指向root的lefttmp = rootroot = root.lefttmp.left = None# 左子树为空,则打印这个节点,并向右边遍历else:res.append(root.val)root = root.rightreturn res

2、二叉树最大深度

在这里插入图片描述

class Solution:def maxDepth(self, root):if root is None:return 0else:left_height = self.maxDepth(root.left)right_height = self.maxDepth(root.right)return max(left_height, right_height) + 1

3、翻转二叉树

在这里插入图片描述

class Solution(object):def invertTree(self, root):# 递归函数的终止条件,节点为空时返回if not root:return None# 将当前节点的左右子树交换root.left, root.right = root.right, root.left# 递归交换当前节点的 左子树和右子树self.invertTree(root.left)self.invertTree(root.right)# 函数返回时就表示当前这个节点,以及它的左右子树# 都已经交换完了return rootclass Solution2(object):def invertTree(self, root):# 迭代方式if not root:return None# 将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素queue = [root]while queue:# 每次都从队列中拿一个节点,并交换这个节点的左右子树tmp = queue.pop(0)tmp.left, tmp.right = tmp.right, tmp.left# 如果当前节点的左子树不为空,则放入队列等待后续处理if tmp.left:queue.append(tmp.left)# 如果当前节点的右子树不为空,则放入队列等待后续处理if tmp.right:queue.append(tmp.right)# 返回处理完的根节点return root

4、对称二叉树

在这里插入图片描述

class Solution(object):def isSymmetric(self, root):if not root:return Truedef dfs(left, right):# 递归的终止条件是两个节点都为空# 或者两个节点中有一个为空# 或者两个节点的值不相等if not (left or right):return Trueif not (left and right):return Falseif left.val != right.val:return False# 分别比较左子节点的左子节点与右子节点的右子节点、左子节点的右子节点与右子节点的左子节点,如果两对节点都对称,则返回True,否则返回False。return dfs(left.left, right.right) and dfs(left.right, right.left)# 用递归函数,比较左节点,右节点return dfs(root.left, root.right)

5、二叉树的直径

在这里插入图片描述
在这里插入图片描述

# 返回二元 tuple (depth, diameter)
# 二叉树的最长路径=max{左子树的最长路径,右子树的最长路径,经过根结点的最长路径}
# 经过根结点的最长路径 = 左子树的深度+右子树的深度
# 所以二叉树的最长路径=max{左子树的最长路径,右子树的最长路径,左子树的深度+右子树的深度}
# depth 表示子树的最大深度,diameter 表示子树的最长路径(直径)
class Solution(object):def diameterOfBinaryTree(self, root):def traverse(root):if root is None:return (0, 0)left_depth, left_diam = traverse(root.left)right_depth, right_diam = traverse(root.right)# 求二叉树深度的常规方法depth = 1 + max(left_depth, right_depth)# 套用上面推导出的最长路径公式diam = max(left_diam, right_diam, left_depth + right_depth)return depth, diamdepth, diam = traverse(root)return diam

6、二叉树层序遍历

在这里插入图片描述
在这里插入图片描述

class Solution(object):def levelOrder(self, root):if not root:return []res = []queue = [root]while queue:# 获取当前队列的长度,这个长度相当于 当前这一层的节点个数size = len(queue)tmp = []# 将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中# 如果节点的左/右子树不为空,也放入队列中for _ in range(size):r = queue.pop(0)tmp.append(r.val)if r.left:queue.append(r.left)if r.right:queue.append(r.right)# 将临时list加入最终返回结果中res.append(tmp)return res# 首先,定义一个用于构建二叉树的简单类
class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = None# 构建一棵二叉树
def build_binary_tree():root = TreeNode(1)root.left = TreeNode(2)root.right = TreeNode(3)root.left.left = TreeNode(4)root.left.right = TreeNode(5)root.right.left = TreeNode(6)return root# 测试代码
solution = Solution()# 创建测试用的二叉树
test_tree = build_binary_tree()# 调用levelOrder方法并打印结果
result = solution.levelOrder(test_tree)
print("层序遍历的结果:", result)# 预期结果是每一层节点值组成的列表
expected_result = [[1], [2, 3], [4, 5, 6]]
assert result == expected_result, "测试失败,实际结果与预期结果不符"

7、将有序数组转为二叉搜索树

在这里插入图片描述

# 二叉搜索树满足两个条件:
# 1)根比左子树大比右子树小;
# 2)高度平衡。因此直接获取有序数组中值作为根就可以,递归生成左子树和右子树即可class Solution(object):def sortedArrayToBST(self, nums):""":type nums: List[int]:rtype: TreeNode"""if len(nums)==0: returnelif len(nums)==1: return TreeNode(nums[0])  #  这个TreeNode会报错,但是不影响在leetcode的判断mid = len(nums)//2node = TreeNode(nums[mid])node.left = self.sortedArrayToBST(nums[:mid])node.right = self.sortedArrayToBST(nums[mid+1:])return node

七、链表

1、合并两个有序链表

在这里插入图片描述

class Solution:def mergeTwoLists(self, l1, l2):if l1 is None:return l2elif l2 is None:return l1elif l1.val < l2.val:l1.next = self.mergeTwoLists(l1.next, l2)return l1else:l2.next = self.mergeTwoLists(l1, l2.next)return l2#  执行不了
# if __name__ == '__main__':
#     l1 = [1, 2, 4]
#     l2 = [1, 3, 4]
#     so = Solution
#     so.mergeTwoLists(l1, l2)

2、相交链表

在这里插入图片描述
在这里插入图片描述

# 暴力解:o(n^2)
# class Solution(object):
#     def getIntersectionNode(self, headA, headB):
#         p = headA
#         while p:
#             q = headB
#             while q:
#                 if p == q:
#                     return p
#                 q = q.next
#             p = p.next
#         return p# 哈希表:先将其中一个链表存到哈希表中,此时再遍历另外一个链表查找重复结点只需 O(1) 时间
class Solution(object):def getIntersectionNode(self, headA, headB):s = set()p, q = headA, headBwhile p:s.add(p)p = p.nextwhile q:if q in s:return qq = q.nextreturn None

3、反转链表

在这里插入图片描述

# 双指针迭代
class Solution(object):def reverseList(self, head):""":type head: ListNode:rtype: ListNode"""# 申请两个节点,pre和 cur,pre指向Nonepre = Nonecur = headwhile cur:# 记录当前节点的下一个节点tmp = cur.next# 然后将当前节点指向precur.next = pre# pre和cur节点都前进一位pre = curcur = tmpreturn pre

4、回文链表

在这里插入图片描述

# 先将链表数据存入到数组arr, 双指针i,j分别从第一个和最后一个从前往后和从后往前遍历
# 相等就继续遍历,直至i > j,如果i和j指向的值不相等,就判断不是回文
class Solution(object):def isPalindrome(self, head):""":type head: ListNode:rtype: bool"""if not (head and head.next):return Truearr, i = [], 0# 申请一个数组,然后把元素都放到数组中while head:_, head = arr.append(head.val), head.nextj = len(arr) - 1# 用i和j两个指针,一个往后,一个往前,不断迭代# 如果i的值不等于j说明不是回文,反之是回文while i < j:if arr[i] != arr[j]:return Falsei, j = i + 1, j - 1return True

5、环形链表

在这里插入图片描述

# # 哈希:我们可以利用set这个数据结构来解决这道题,首先定义一个Set。
# # 之后遍历链表的节点,每遍历一个节点,就将这个节点的元素放入set中,如果这个链表没有环,那么最终遍历就结束了。
# # 如果链表有环的话,那么肯定有一个元素会被访问两次,当第二次访问这个元素的时候,set中就有记录了,这样就可以判断出链表是否有环了。
# class Solution(object):
#     def hasCycle(self, head):
#         # 定义一个set,然后不断遍历链表
#         s = set()
#         while head:
#             # 如果某个节点在set中,说明遍历到重复元素了,也就是有环
#             if head in s:
#                 return True
#             s.add(head)
#             head = head.next
#         return False# 快慢指针解法
# 按照这个思路,我们可以假设有a和b两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合的
class Solution(object):def hasCycle(self, head):""":type head: ListNode:rtype: bool"""if not (head and head.next):return False# 定义两个指针i和j,i为慢指针,j为快指针i, j = head, head.nextwhile j and j.next:if i == j:return True# i每次走一步,j每次走两步i, j = i.next, j.next.nextreturn False

6、两数相加

在这里插入图片描述
在这里插入图片描述

# 我们不断的遍历两个链表,每次遍历都将链表a和链表b的值相加,再赋给链表a。如果有进位我们还需要记录一个进位标志。
# 循环的条件是链表a不为空或者链表b不为空,这样当整个循环结束时,链表就被串起来了。
# 当循环结束时,如果进位标志>0还需要处理下边界条件。
# 我们不用生成一个新的节点,直接将两个节点相加的值赋给节点a就可以了,这样只用改变节点的内容,速度会更快一些。class Solution(object):def addTwoNumbers(self, l1, l2):# 定义一个进位标志a, b, p, carry = l1, l2, None, 0while a or b:# a和b节点的值相加,如果有进位还要加上进位的值val = (a.val if a else 0) + (b.val if b else 0) + carry# 根据val判断是否有进位,不管有没有进位,val都应该小于10carry, val = val / 10 if val >= 10 else 0, val % 10p, p.val = a if a else b, val# a和b指针都前进一位a, b = a.next if a else None, b.next if b else None# 根据a和b是否为空,p指针也前进一位p.next = a if a else b# 不要忘记最后的边界条件,如果循环结束carry>0说明有进位需要处理这个条件if carry:p.next = ListNode(carry)# 每次迭代实际上都是将val赋给a指针的,所以最后返回的是l1return l1

八、二分查找

1、搜索插入位置

在这里插入图片描述

class Solution:def searchInsert(self, nums, target):left, right = 0, len(nums)  # 采用左闭右开区间[left,right)while left < right:         # 右开所以不能有=,区间不存在mid = left + (right - left) // 2  # 防止溢出, //表示整除if nums[mid] < target:  # 中点小于目标值,在右侧,可以得到相等位置left = mid + 1  # 左闭,所以要+1else:right = mid  # 右开,真正右端点为mid-1return left  # 此算法结束时保证left = right,返回谁都一样if __name__ == '__main__':nums = [1, 2, 3, 4, 5, 6, 8]target = 5so= Solution()print(so.searchInsert(nums, target))

2、搜索二维矩阵

在这里插入图片描述

# # 暴力解:直接遍历
# class Solution(object):
#     def searchMatrix(self, matrix, target):
#         """
#         :type matrix: List[List[int]]
#         :type target: int
#         :rtype: bool
#         """
#         M, N = len(matrix), len(matrix[0])
#         for i in range(M):
#             for j in range(N):
#                 if matrix[i][j] == target:
#                     return True
#         return False# 如果 target 大于这一行的末尾元素,那么target 一定不在这一行中,只能出现在矩阵的下面的行中。
# 那么,假如 target < matrix[i][N - 1]时,说明 target 可能在本行中出现,而且由于下面各行的元素都大于 matrix[i][N - 1] ,
# 所以,不可能在下面的行中出现。此时,可以在本行中使用顺序查找,或者二分查找。
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])for i in range(M):if target > matrix[i][N - 1]:continueif target in matrix[i]:return Truereturn Falseif __name__ == '__main__':matrix  = [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 60]]so = Solution()print(so.searchMatrix(matrix, 3))

3、在排序数组中找到元素的第一个位置和最后一个位置

在这里插入图片描述

# 找到相同的元素即为起始索引,向后一直找到终止索引
class Solution:def searchRange(self, nums, target):for i in range(len(nums)):if nums[i] == target:j = i + 1while j < len(nums) and nums[j] == target:j += 1return [i, j-1]return [-1, -1]if __name__ == '__main__':nums = [5, 7, 7, 8, 8, 10]target = 8so = Solution()print(so.searchRange(nums, target))

九、矩阵

1、矩阵置0

在这里插入图片描述

# 遍历一次矩阵,记录一下每行、列是否出现了 0,分别记录行值和列值;
# 第二次遍历,如果行值或者列值出现在去重集合中,则将矩阵所在点的值置0
class Solution:def setZeroes(self, matrix):if not matrix or not matrix[0]:returnM, N = len(matrix), len(matrix[0])row, col = set(), set()for i in range(M):for j in range(N):if matrix[i][j] == 0:row.add(i)col.add(j)for i in range(M):for j in range(N):if i in row or j in col:matrix[i][j] = 0if __name__ == '__main__':matrix = [[1, 1, 1], [1, 0, 1], [1, 1, 1]]so =Solution()print(so.setZeroes(matrix))

10、栈

1、有效括号

在这里插入图片描述

# 通过栈,使用右括号匹配左括号
class Solution:def isValid(self, s):dic = {')': '(', ']': '[', '}': '{'}stack = []for i in s:if stack and i in dic:if stack[-1] == dic[i]:stack.pop()else:return Falseelse:stack.append(i)# 使用not stack 代替 True可以减少计算S只有一位的值的测试数据return not stackif __name__ == '__main__':so = Solution()# s = "()[]{}"s = "{()[()]}"print(so.isValid(s))

11、贪心算法

1、股票买卖的最佳时期

在这里插入图片描述

class Solution:def maxProfit(self, prices: List[int]) -> int:minprice = float('inf')maxprofit = 0for price in prices:minprice = min(minprice, price)maxprofit = max(maxprofit, price - minprice)return maxprofit

12、动态规划

1、杨辉三角

在这里插入图片描述

class Solution:def generate(self, numRows: int):triangle = []for i in range(numRows):row = [1] * (i + 1)if i >= 2:for j in range(1, i):row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j]triangle.append(row)return triangleif __name__ == '__main__':numRows = 5so = Solution()print(so.generate(numRows))

13、技巧

1、只出现一次的数字

在这里插入图片描述

# 异或解法:异或运算满足交换律,a^b^a=a^a^b=b,因此ans相当于nums[0]^nums[1]^nums[2]^nums[3]^nums[4].....
# 然后再根据交换律把相等的合并到一块儿进行异或(结果为0),然后再与只出现过一次的元素进行异或,这样最后的结果就是,只出现过一次的元素(0^任意值=任意值)
class Solution(object):def singleNumber(self, nums):""":type nums: List[int]:rtype: int"""ans = nums[0]if len(nums) > 1:for i in range(1, len(nums)):ans = ans ^ nums[i]return ansif __name__ == '__main__':# nums = [2, 2, 1]# nums = [2, 2, 1, 1, 5]nums = [2, 3, 4, 3, 4]so = Solution()print(so.singleNumber(nums))

2、多数元素

在这里插入图片描述

# 时间复杂度O(nlogn)
# class Solution(object):
#     def majorityElement(self, nums):
#         """
#         :type nums: List[int]
#         :rtype: int
#         """
#         nums.sort()
#         return nums[len(nums)//2]# 时间复杂度:O(n),空间复杂度:O(M)
class Solution(object):def majorityElement(self, nums):dict = {}for i in nums:if i in dict:dict[i] = dict[i] + 1else:dict[i] = 1maxval = max(dict.values())# print(maxval)for key, val in dict.items():if dict[key] == maxval:return keyif __name__ == '__main__':# nums = [2, 2, 1, 1, 1, 2, 2]nums = [3, 3, 4]so = Solution()print(so.majorityElement(nums))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/548779.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【高通camera hal bug分析】高通自带相机镜像问题

首先打了两个log&#xff0c;一个是开启镜像的log&#xff0c;还有一个是没有开启镜像的log&#xff0c;如果我们开启镜像以后&#xff0c;观察开启镜像log发现 , 这段代码走的没有任何问题&#xff0c;因为Flip的值等于1了。 关闭镜像log如下&#xff1a; 如果我们不开启镜像…

2024-3-18 市场情绪高潮

竞价最大亮点就是 永悦科技 顶一字超预期&#xff0c;上周五带动了低空经济板块&#xff0c;今天直接一字走加速&#xff0c;pk掉了同身位的 大理药业&#xff0c;把 艾艾精工 的强分歧也顶回去了&#xff0c;所以核心是 永悦科技&#xff0c;题材上 设备更新的废固处理继续&am…

【全网最详细】ComfyUI下,Insightface安装指南-聚梦小课堂

&#x1f96e;背景 ComfyUI下使用IP-adapter下的faceID模型的时候&#xff0c;大家可能会遇到如下错误&#xff1a; Error occurred when executing InsightFaceLoader: No module named insightface File "F:\ComfyUI-aki\execution.py", line 151, in recursive_…

浅谈如何自我实现一个消息队列服务器(2)——细节详解

文章目录 一、实现 broker server 服务器1.1 创建一个SpringBoot项目1.2 创建Java类 二、硬盘持久化存储 broker server 里的数据2.1 数据库存储2.1.1 浅谈SQLiteMyBatis 2.1.2 如何使用SQLite 2.2 文件存储 三、将broker server 里的数据存储在内存上四、使用DataBaseManager类…

java 线上生产问题排查思路,jvm内存溢出实例重启原因排查生产实战

java jvm内存溢出实例重启排查生产实战&#xff08;使用VisualVM&#xff09; 背景 项目组线上生产环境不定期的发生内存爆满然后实例重启&#xff0c;实例发布上线后实例内存不断增长最后维持在百分之九十多&#xff0c;十分危险。因此我参与到了排查中&#xff0c;本篇博客将…

TTS 擂台: 文本转语音模型的自由搏击场

对文本转语音 (text-to-speech, TTS) 模型的质量进行自动度量非常困难。虽然评估声音的自然度和语调变化对人类来说是一项微不足道的任务&#xff0c;但对人工智能来说要困难得多。为了推进这一领域的发展&#xff0c;我们很高兴推出 TTS 擂台。其灵感来自于LMSys为 LLM 提供的…

08|记忆:通过Memory记住客户上次买花时的对话细节

无论是LLM还是代理都是无状态的&#xff0c;每次模型的调用都是独立于其他交互的。也就是说&#xff0c;我们每次通过API开始和大语言模型展开一次新的对话&#xff0c;它都不知道你其实昨天或者前天曾经和它聊过天了。 使用ConversationChain from langchain import OpenAI…

C语言例:表达式 45-35+1^2 的值

代码如下&#xff1a; #include<stdio.h> int main(void) {int a;a 4&5-3&&51^2;printf("4&5-3&&51^2 %d\n",a);return 0; } 结果如下&#xff1a;

18 优先级队列

priority_queue介绍 1.优先级队列是一种容器适配器&#xff0c;根据弱排序标准&#xff0c;它的第一个元素总是最大的 2.此上下文类似于堆&#xff0c;堆中可以随时插入元素&#xff0c;检索最大堆元素 3.优先队列实现为容器适配器&#xff0c;容器适配器即将特定容器类封装作…

代码随想录|Day23|回溯03|39.组合总和、40.组合总和II、131.分割回文串

39.组合总和 本题和 216.组合总和III 类似&#xff0c;但有几个区别&#xff1a; 没有元素个数限制&#xff1a;树的深度并不固定&#xff0c;因此递归终止条件有所变化每个元素可以使用多次&#xff1a;下层递归的起始位置和上层相同&#xff08;startIndex不需要改动&#xf…

PostgreSQL中vacuum 物理文件truncate发生的条件

与我联系&#xff1a; 微信公众号&#xff1a;数据库杂记 个人微信: iiihero 我是iihero. 也可以叫我Sean. iiheroCSDN(https://blog.csdn.net/iihero) Sean墨天轮 (https://www.modb.pro/u/16258) 数据库领域的资深爱好者一枚。 水木早期数据库论坛发起人 db2smth就是俺&am…

特约撰稿 | 李杰:2024快消品牌企业如何赢在数字化?

随着用户群体、消费场景的细分&#xff0c;以及渠道的进一步多元化&#xff0c;让快消品企业遇到了一些机遇与挑战&#xff0c;在这样的大趋势之下&#xff0c;2024年快消品牌企业&#xff0c;要脱颖而出赢得增长&#xff0c;必须要把握战略上的机会。 作者&#xff5c;纷享销…