每日刷题

    • 刷题模板
      • 背包问题
  • 简单题
    • 1.两数之和
    • 2.两数相加
    • 70.爬楼梯(动态规划)
    • 94.二叉树的中序遍历
    • 101.对称二叉树
    • 104二叉树的最大深度
    • 121.买卖股票的最佳时机
    • 136.只出现一次的数字
    • 141.环形链表(快慢指针)
    • 155.最小栈(栈)
    • 160.相交链表(前后指针)
    • 169.多数元素
    • 169.多数元素
    • 206反转链表
    • 226翻转二叉树
    • 234回文链表
    • 283移动零
    • 338比特位计数
    • 448.找到所有数组中消失的数字
    • 461.汉明距离
    • 543.二叉树的直径
    • 617.合并二叉树
  • 中等题
    • 2.两数相加
    • 3.无重复字符的最长子串
    • 5.最长回文子串
    • 11.盛最多水的容器
    • 15.三数之和
    • 17.电话号码的字母组合
    • 19.删除链表的倒数第n个结点
    • 22.括号生成
    • 31.下一个排列
    • 33.搜索旋转排序数组
    • 34.在排序数组中查找元素的第一个和最后一个位置
    • 39.组合总和
    • 46.全排列
    • 48.旋转图像
    • 49.字母异位词分组
    • 55.跳跃游戏
    • 56.合并区间
    • 62.不同路径
    • 64.最小路径和
    • 75.颜色分类
    • 78.子集
    • 79.单词搜索
    • 96.不同的二叉搜索树
    • 98.验证二叉搜索树
    • 102.二叉树的层序遍历
    • 105.从前序与中序遍历序列构造二叉树
    • 114.二叉树展开为链表
    • 128.最长连续序列
    • 139.单词拆分
    • 142.环形链表2
    • 146.LRU缓存
    • 148.排序链表(分治法)
    • 152.乘积最大子数组
    • 198.打家劫舍
    • 200.岛屿数量
    • 207.课程表
    • 208实现Trie(前缀树)
    • 215.数组中的第K个最大元素
    • 221.最大正方形
    • 236.二叉树的最近公共祖先
    • 238.除自身以外数组的乘积
    • 240.搜索二维矩阵2
    • 279.完全平方数
    • 标题287.寻找重复数
    • 300.最长递归子序列
    • 309.最佳买卖股票时机含冷冻期
    • 322.零钱兑换
    • 337.打家劫舍3
    • 347.前k个高频元素

刷题模板

背包问题

背包问题大体的解题模板是两层循环,分别遍历物品nums和背包容量
target,然后写转移方程, 根据背包的分类我们确定物品和容量遍历的先后顺序,根据问题的分类我们确定状态转移方程的写法

首先是背包分类的模板:
1、0/1背包:外循环nums,内循环target,target倒序且target>=nums[i];
2、完全背包:外循环nums,内循环target,target正序且target>=nums[i];
3、组合背包(考虑顺序):外循环target,内循环nums,target正序且target>=nums[i];
4、分组背包:这个比较特殊,需要三重循环:外循环背包bags,内部两层循环根据题目的要求转化为1,2,3三种背包类型的模板

然后是问题分类的模板:
1、最值问题: dp[i] = max/min(dp[i], dp[i-nums]+1)或dp[i] = max/min(dp[i], dp[i-num]+nums);
2、存在问题(bool):dp[i]=dp[i]||dp[i-num];
3、组合问题:dp[i]+=dp[i-num];

简单题

1.两数之和

#暴力枚举方法
先从列表中找到其中一个,再找到另外一个使之两个的和等于目标值,需要重复遍历两次,时间复杂度为n^2,空间复杂度为1
class Solution:def twoSum(self, nums,target):n = len(nums)for i in range(n):for j in range(i + 1,n):if nums[i] + nums[j] == target:return i,j
#哈希表
#创建一个哈希表,对于每一个x,我们首先查询哈希表中是否存在target-x,然后将x插入到哈希表中,即可保证不会让x和自己匹配,时间复杂度n,空间复杂度n
class Solution:def twoSum(self,nums,target):hashtable = dict()for i,num in enumerate(nums):  #enumerate 用于遍历,同时列出数据和数据下标if target - num in hashtable:return [hashtable[target - num],i]hashtable[nums[i]] = ireturn []

2.两数相加

#单向链表,模拟加法进位操作
class Solution:def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:# 初始化个位节点,先不做进位newPoint = ListNode(l1.val + l2.val)# rt用来作为最后return的节点,tp用来遍历节点rt, tp = newPoint, newPoint# l1,l2只要后面还有节点,就继续往后遍历;或者新链表还需要继续往后进位while (l1 and (l1.next != None)) or (l2 and (l2.next != None)) or (tp.val > 9):l1, l2 = l1.next if l1 else l1, l2.next if l2 else l2tmpsum = (l1.val if l1 else 0) + (l2.val if l2 else 0)# 计算新链表下个节点的值(当前节点的进位+当前l1 l2的值之和),先不做进位tp.next = ListNode(tp.val//10 + tmpsum)# 新链表当前节点的值取个位tp.val %= 10# 新链表往后便利一个节点tp = tp.nextreturn rt

70.爬楼梯(动态规划)

第n个台阶只能从第n-1或者第n-2个上来,到第n-1个台阶的走法+第n-2个台阶的走法=到第n个台阶的走法,已经知道了第1个和第2个台阶的走法,一路加上去

class Solution:def climbstairs(self,n):if n==1 or n==2:return na = 1b = 2 #a表示第n-1个台阶的走法,b表示第n-2个台阶的走法,传统迭代count = 0for i in range(3,n+1):count = a + b #累加结果#向下迭代a = b #下次迭代的第n-2个台阶的走法等于上次迭代的n-1个台阶的走法b = count #下次迭代的第n-1个台阶的走法等于上次迭代的第n个台阶走法return count

94.二叉树的中序遍历

二叉树的中序遍历就是首先遍历左子树,然后访问当前节点,最后遍历右子树。

#递归做法:递归遍历左子树,访问根节点,递归遍历右子树
#非递归过程:先访问..最左子树..结点,再访问其父节点,再访问其兄弟
#中序遍历不忘“左链入栈”
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#迭代法
#https://www.bilibili.com/video/BV11P4y1L7in?from=search&seid=13963080210323760588&spm_id_from=333.337.0.0
class Solution:def inorderTraversal(self, root: TreeNode) -> List[int]: stack,ret = [],[] #创建空栈和结果集cur = root #用cur代表当前的根节点while stack or cur:#中序遍历需先判断当前的栈是否还有元素或者当前的栈是否为空,说明走完了退出当前循环if cur:  #若存在则将该节点放入栈中stack.append(cur)cur = cur.left  #再将当前结点设置为结点的左孩子else:  #这时候的当前结点已经是最左边的孩子了,左边儿没有了cur = stack.pop()# 则取栈顶元素为curret.append(cur.val)#当且仅当栈空cur也为空,循环结束。cur = cur.rightreturn ret# 前序遍历-递归-LC144_二叉树的前序遍历
class Solution:def preorderTraversal(self, root: TreeNode) -> List[int]:# 保存结果result = []def traversal(root: TreeNode):if root == None:returnresult.append(root.val) # 前序traversal(root.left)    # 左traversal(root.right)   # 右traversal(root)return result# 中序遍历-递归-LC94_二叉树的中序遍历
class Solution:def inorderTraversal(self, root: TreeNode) -> List[int]:result = []def traversal(root: TreeNode):if root == None:returntraversal(root.left)    # 左result.append(root.val) # 中序traversal(root.right)   # 右traversal(root)return result# 后序遍历-递归-LC145_二叉树的后序遍历
class Solution:def postorderTraversal(self, root: TreeNode) -> List[int]:result = []def traversal(root: TreeNode):if root == None:returntraversal(root.left)    # 左traversal(root.right)   # 右result.append(root.val) # 后序traversal(root)return result

101.对称二叉树

递归的难点在于:找到可以递归的点 为什么很多人觉得递归一看就会,一写就废。 或者说是自己写无法写出来,关键就是你对递归理解的深不深。

对于此题: 递归的点怎么找?从拿到题的第一时间开始,思路如下:

1.怎么判断一棵树是不是对称二叉树? 答案:如果所给根节点,为空,那么是对称。如果不为空的话,当他的左子树与右子树对称时,他对称

2.那么怎么知道左子树与右子树对不对称呢?在这我直接叫为左树和右树 答案:如果左树的左孩子与右树的右孩子对称,左树的右孩子与右树的左孩子对称,那么这个左树和右树就对称。

仔细读这句话,是不是有点绕?怎么感觉有一个功能A我想实现,但我去实现A的时候又要用到A实现后的功能呢?

当你思考到这里的时候,递归点已经出现了: 递归点:我在尝试判断左树与右树对称的条件时,发现其跟两树的孩子的对称情况有关系。

想到这里,你不必有太多疑问,上手去按思路写代码,函数A(左树,右树)功能是返回是否对称

def 函数A(左树,右树): 左树节点值等于右树节点值 且 函数A(左树的左子树,右树的右子树),函数A(左树的右子树,右树的左子树)均为真 才返回真

二叉树是否对称可以转化为左右子树是否镜像

class Solution(object):def isSymmetric(self, root):""":type root: TreeNode:rtype: bool"""#递归#创建一个函数:1.判断A的值和B的值是否相等
#2.A的左子树和B的右子树是否相等  与   A的右子树和B的左子树是否相等def check(A,B):  #判断数A和树B是否镜像if not A and not B:return Trueelif not A or not B:return Falseif A.val != B.val:return Falsereturn check(A.left,B.right) and check(A.right,B.left)return check(root,root)#迭代:就是层序遍历,检查每一层是不是回文数组class Solution(object):def isSymmetric(self, root):""":type root: TreeNode:rtype: bool"""       queue = [root]while(queue):next_queue = list()layer = list()for node in queue:if not node:layer.append(None)   #空的补充nullcontinuenext_queue.append(node.left)next_queue.append(node.right)layer.append(node.val)if layer != layer[::-1]:  #回文数前后判断return Falsequeue = next_queuereturn True

104二叉树的最大深度

第一种方法:BFS广度优先搜索,使用双端队列deque(因为性能比另外两种Queue好的多),在大循环内对二叉树的每个层做一次遍历,range(len(queue))使只遍历当前的层,每次大循环ans加1.由于每个节点仅访问一次,所以时间复杂度为O(n)

import collections
class Solution:def maxDepth(self,root):if root is None:return 0queue = collections.deque()queue.append(root)ans = 0while queue:ans += 1for _ in range(len(queue)):node = queue.popleft()if node.left:queue.append(node.left)if node.right:queue.append(node.right)return ans

第二种方法:DFS深度优先搜索,利用递归的栈,借助level标记当前层,由于每个节点仅访问一次,所以时间复杂度O(n)

class Solution:def maxDepth(slef,root):if not root:return 0self.ans = 0self._dfs(root,0)return self.ansdef _dfs(self,node,level):if not node:returnif self.ans < level + 1:self.ans = level + 1self._dfs(node.left,level + 1)self._dfs(node.right,level + 1)

第三种方法迭代:DSF+分治,耗时

class Solution:def maxDepth(self,root):if not root:return 0return 1 + max(self.maxDepth(root.left),self.maxDepth(root.right))

121.买卖股票的最佳时机

动态规划:

前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-第i-1天中的最小价格}

解题思路
到最后交易结束时,一共会有3种状态:

dp0:一直不买
dp1:只买了一次
dp2:买了一次,卖了一次

初始化3种状态:
dp0 = 0
dp1 = - prices[0]
dp2 = float("-inf")
因为第一天不可能会有dp2状态,因此将dp2置为负无穷
(Java中置为int的下边界)

对3种状态进行状态转移:
#一直为0
dp0 = 0
#前一天也是dp1状态,或者前一天是dp0状态,今天买入一笔变成dp1状态
dp1 = max(dp1, dp0 - prices[i])
#前一天也是dp2状态,或者前一天是dp1状态,今天卖出一笔变成dp2状态
dp2 = max(dp2, dp1 + prices[i])
最后一定是手里没有股票赚的钱最多,因此返回的是dp0,dp2的最大值

class Solution:def maxProfit(self, prices: List[int]) -> int:dp0 = 0             # 一直不买dp1 = - prices[0]   # 只买了一次dp2 = float('-inf') # 买了一次,卖了一次for i in range(1, len(prices)):dp1 = max(dp1, dp0 - prices[i])  #存放最低的成本dp2 = max(dp2, dp1 + prices[i])  #存放最大的利润return max(dp0, dp2)

136.只出现一次的数字

不需要额外空间的方法,就往位运算上想
1.交换律:a ^ b ^ c<=>a ^ c ^ b
2.任何数与0异或为任何数0 ^ n => n
3.相同的数异或为0:n ^ n => 0
var a = [2,3,2,4,4]
2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3

class Solution:def singleNumber(self, nums: List[int]) -> int:a = 0for num in nums:a = a ^ numreturn a

141.环形链表(快慢指针)

class Solution:def hasCycle(self, head: Optional[ListNode]) -> bool:if head is None:return Falsefast,slow = head,headwhile fast and fast.next:slow = slow.nextfast = fast.next.nextif slow == fast:return Truereturn False

155.最小栈(栈)

一个栈同时保存当前值和栈内最小值
思路:题目要求在常数时间内获得栈中的最小值,因此不能在 getMin() 的时候再去计算最小值,最好应该在 push 或者 pop 的时候就已经计算好了当前栈中的最小值。
可以用一个栈,这个栈同时保存的是每个数字 x 进栈的时候的值 与 插入该值后的栈内最小值。即每次新元素 x 入栈的时候保存一个元组:(当前值 x,栈内最小值)。

这个元组是一个整体,同时进栈和出栈。即栈顶同时有值和栈内最小值,top()函数是获取栈顶的当前值,即栈顶元组的第一个值; getMin() 函数是获取栈内最小值,即栈顶元组的第二个值;pop() 函数时删除栈顶的元组。

每次新元素入栈时,要求新的栈内最小值:比较当前新插入元素 x 和 当前栈内最小值(即栈顶元组的第二个值)的大小。

新元素入栈:当栈为空,保存元组 (x, x);当栈不空,保存元组 (x, min(此前栈内最小值, x)))
出栈:删除栈顶的元组。

class MinStack:def __init__(self):self.stack = [] #放元组def push(self, val: int) -> None:if self.stack is None:self.stack.append((val,val))  #为空,保存元祖else:self.stack.append((val,min(val,self.stack[-1][1])))#stack[-1]代表stack中倒数第一个元组,stack[-1][1]指的是元组中的第二个元素def pop(self) -> None:self.stack.pop()def top(self) -> int:return self.stack[-1][0]def getMin(self) -> int:return self.stack[-1][1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

160.相交链表(前后指针)

有交集的时候儿:
a+c+b=b+c+a
没有交集的时候儿:
第一个指针在a循环完了会循环b,第二个指针在b循环完了会去循环a,没有交点的话两个指针走的路程是一样的都是a+b,所以最后会同时走到最后一个节点,然后在next,就都到null了,相等,就会返回null

class Solution:def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:A, B = headA, headBwhile A != B:A = A.next if A else headBB = B.next if B else headAreturn A

169.多数元素

摩尔投票法(Boyer–Moore majority vote algorithm),也被称作「多数投票法」,算法解决的问题是:如何在任意多的候选人中(选票无序),选出获得票数最多的那个。
算法可以分为两个阶段:
对抗阶段:分属两个候选人的票数进行两两对抗抵消
计数阶段:计算对抗结果中最后留下的候选人票数是否有效

class Solution:def majorityElement(self, nums: List[int]) -> int:major = 0count = 0for n in nums:if count == 0:major = nif major == n:count += 1else:count -= 1return major

169.多数元素

摩尔投票法(Boyer–Moore majority vote algorithm),也被称作「多数投票法」,算法解决的问题是:如何在任意多的候选人中(选票无序),选出获得票数最多的那个。
算法可以分为两个阶段:
对抗阶段:分属两个候选人的票数进行两两对抗抵消
计数阶段:计算对抗结果中最后留下的候选人票数是否有效

class Solution:def majorityElement(self, nums: List[int]) -> int:major = 0count = 0for n in nums:if count == 0:major = nif major == n:count += 1else:count -= 1return major

206反转链表

前置条件:迭代指针:p = head、结果指针:res = none

以1->2->3->4->5为例:

过程:

res:None

第一层循环

res:1->2->3->4->5 res = p

res:1->None res.next = res

p:2->3->4->5 p = p.next

第二层循环

res:2->3->4->5 res = p

res:2->1->None res.next = res

p:3->4->5 p = p.next

第三层循环

res:3->4->5 res = p

res:3->2->1->None res.next = res

p:4->5 p = p.next

第四层循环

res:4->5 res = p

res:4->3->2->1->None res.next = res

p:5 p = p.next

第五层循环

res:5 res = p

res:5->4->3->2->1->None res.next = res

p:None p = p.next

end…

class Solution:def reverseList(self, head: ListNode) -> ListNode:p, rev = head, Nonewhile p:rev, rev.next, p = p, rev, p.nextreturn rev

226翻转二叉树

class Solution:def invertTree(self, root: TreeNode) -> TreeNode:if root is None:return Noneroot.left,root.right = root.right, root.left self.invertTree(root.left)self.invertTree(root.right)#这时候儿左右节点都已经交换过了return root

234回文链表

class Solution:def isPalindrome(self, head: ListNode) -> bool:stack = []cur = headwhile cur:stack.append(cur.val)cur = cur.nextreturn stack == stack[::-1]

283移动零

class Solution:def moveZeroes(self, nums: List[int]) -> None:for n in range(nums.count(0)):nums.remove(0)nums.append(0)
#快慢指针方法
class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""right = left = 0while right < len(nums):if nums[right]:nums[right],nums[left] = nums[left],nums[right]left += 1right += 1

338比特位计数

class Solution:def countBits(self, n):""" 1: 0001     3:  0011      0: 00002: 0010     6:  0110      1: 00014: 0100     12: 1100      2: 0010 8: 1000     24: 11000     3: 001116:10000    48: 110000    4: 010032:100000   96: 1100000   5: 0101由上可见:1、如果 i 为偶数,那么f(i) = f(i/2) ,因为 i/2 本质上是i的二进制左移一位,低位补零,所以1的数量不变。2、如果 i 为奇数,那么f(i) = f(i - 1) + 1, 因为如果i为奇数,那么 i - 1必定为偶数,而偶数的二进制最低位一定是0,那么该偶数 +1 后最低位变为1且不会进位,所以奇数比它上一个偶数bit上多一个1,即 f(i) = f(i - 1) + 1。      """ret = [0]for i in range(1, n + 1):if i % 2 == 0: # 偶数ret.append(ret[i//2])  #整除else: # 奇数ret.append(ret[i - 1] + 1)return ret

448.找到所有数组中消失的数字

     counter = set(nums)  #进行去重N = len(nums)res = []for i in range(1, N + 1):if i not in counter:res.append(i)return res #数组的原地操作class Solution(object):def findDisappearedNumbers(self, nums):""":type nums: List[int]:rtype: List[int]"""for i, num in enumerate(nums):if nums[abs(num) - 1] > 0:nums[abs(num) - 1] *= -1res = []for i in range(len(nums)):if nums[i] > 0:res.append(i + 1)return res

461.汉明距离

class Solution:def hammingDistance(self, x: int, y: int) -> int:return bin(x ^ y).count('1')#bin把10进制数转化为二进制数,count()计算字符串中指定字符个数

543.二叉树的直径

class Solution:def diameterOfBinaryTree(self, root: TreeNode) -> int:self.depth(root)return self.maxdef __init__(self):self.max = 0def depth(self,root):if root is None:return 0l = self.depth(root.left)r = self.depth(root.right)'''每个结点都要去判断左子树+右子树的高度是否大于self.max,更新最大值'''self.max = max(self.max,l + r)# 返回的是高度

617.合并二叉树

#递归
class Solution:def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:if root1 and root2:root1.val += root2.valroot1.left = self.mergeTrees(root1.left,root2.left)root1.right = self.mergeTrees(root1.right,root2.right) return root1return root1 or root2

中等题

2.两数相加

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:#生成一个值为0的链表作为表头self.head = ListNode(0)#首尾为同一个节点self.tail = self.head#记录单个位置是否进位的变量,初始为0,值应该在0,1之前切换carry=0while(l1 or l2):  #循环条件,判断给的节点是否存在# 接收l1节点value的变量,如果l1节点为空则值为0x= l1.val if l1 else 0# 接收l2节点value的变量,如果l2节点为空则值为0y= l2.val if l2 else 0#将进位值与两个节点value相加s=carry+x+y#取本次节点相加进位值,决定下次循环时进位值carry=s//10#将目前节点的next(tail默认为None)改为计算后的个位数放入的节点self.tail.next=ListNode(s%10)#将计算节点放入列表尾部self.tail=self.tail.next#如果l1/l2存在,将next值传入l1/l2.节点存在才有nextif l1:l1=l1.nextif l2:l2=l2.next#如果最高位的计算仍然是2位数,将进位1作为节点出入最尾部if(carry>0):self.tail.next=ListNode(1) #这里的self.head.next即指向了第二个节点,将我们生成的0节点排除return self.head.next

3.无重复字符的最长子串

class Solution:def lengthOfLongestSubstring(self, s: str) -> int:a = []res = 0for i in s:if i in a:a = a[a.index(i)+1:] #切片操作,从重复字符的位置切到当前元素#后面的代码里a会append当前元素,最后得到的新a就是当前元素的最长不重复字串a.append(i)res = res if len(a)<res else len(a)return res

5.最长回文子串

class Solution:def longestPalindrome(self, s: str) -> str:l = len(s)if l < 2:return sfor i in range(l, 0, -1):for j in range(l-i+1):son_s = s[j:j+i]if son_s == son_s[::-1]:return son_sreturn ''
#中心扩散法
class Solution:def longestPalindrome(self, s: str) -> str:n, m = 0, 0for i in range(len(s)):left, right = i, iwhile left >= 0 and s[left] == s[i]: left -= 1while right < len(s) and s[right] == s[i]: right += 1while left >= 0 and right < len(s) and s[left] == s[right]:left -= 1right += 1if m - n + 1 < right - left - 1:n, m = left + 1, right - 1return s[n:m+1]

11.盛最多水的容器

class Solution:def maxArea(self, height: List[int]) -> int:l, r = 0, len(height) - 1ans = 0while l < r:area = min(height[l], height[r]) * (r - l)ans = max(ans, area)if height[l] <= height[r]:  # 移动较小的那一端l += 1else:r -= 1return ans

15.三数之和

class Solution:def threeSum(self, nums: [int]) -> [[int]]:nums.sort()#  排序,nums变成递增数组res, k = [], 0for k in range(len(nums) - 2):  #-2是为了保证后面还能存在两个数字if nums[k] > 0: break # 若nums[k]大于0,则后面的数字也是大于零(排序后是递增的)if k > 0 and nums[k] == nums[k - 1]: continue #nums[k]值重复了,去重i, j = k + 1, len(nums) - 1   #定义左右指针while i < j: # 3. double pointers = nums[k] + nums[i] + nums[j]  if s < 0:i += 1  #左指针前进并去重while i < j and nums[i] == nums[i - 1]: i += 1elif s > 0:j -= 1  #右指针后退并去重while i < j and nums[j] == nums[j + 1]: j -= 1else:res.append([nums[k], nums[i], nums[j]])i += 1j -= 1while i < j and nums[i] == nums[i - 1]: i += 1 #左指针前进并去重while i < j and nums[j] == nums[j + 1]: j -= 1  #右指针后退并去重return res

17.电话号码的字母组合

class Solution(object):def letterCombinations(self, digits):"""动态规划dp[i]: 前i个字母的所有组合由于dp[i]只与dp[i-1]有关,可以使用变量代替列表存储降低空间复杂度:type digits: str:rtype: List[str]"""if not digits:return []d = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl','6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'}n = len(digits)dp = [[] for _ in range(n)]dp[0] = [x for x in d[digits[0]]]for i in range(1, n):dp[i] = [x + y for x in dp[i - 1] for y in d[digits[i]]]return dp[-1]def letterCombinations2(self, digits):"""使用变量代替上面的列表降低空间复杂度:type digits: str:rtype: List[str]"""if not digits:return []d = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl','6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'}n = len(digits)res = ['']for i in range(n):res = [x + y for x in res for y in d[digits[i]]]return resdef letterCombinations3(self, digits):"""递归:param digits::return:"""d = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl','6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'}if not digits:return []if len(digits) == 1:return [x for x in d[digits[0]]]return [x + y for x in d[digits[0]] for y in self.letterCombinations3(digits[1:])]

19.删除链表的倒数第n个结点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:#双指针a = headb = headfor i in range(n):  #距离为n,提前后移动n个节点if a.next:a = a.next  else:  #移除的是首结点return head.nextwhile a.next:#当a到达链表尾,b指向要删除的节点的前一个节点a = a.next b = b.next#因为已经保证了是待删除节点的前一个节点,直接删除即可b.next = b.next.next  #删除b指针所指节点后的节点return head

22.括号生成

class Solution:def generateParenthesis(self, n: int) -> List[str]:result = {""}for i in range(n):temp = set()for s in result:#在上一次的结果的所有字符串的各个位置上插入“()”for j in range(len(s) + 1):temp.add(s[:j] + "()" + s[j:])result = tempreturn list(result)
#回溯算法
class Solution:def generateParenthesis(self, n: int) -> List[str]:res = []def backTracking(left, right, s):if len(s) == 2*n:res.append(s)return if left < n:backTracking(left+1, right, s+'(')if right < left:backTracking(left, right+1, s+')')backTracking(0,0,'')return res

31.下一个排列

class Solution:def nextPermutation(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""for i in range(len(nums)-1,0,-1):# 对应第3部,找到下标l的位置,这里 l == i-1if nums[i-1] < nums[i]:for j in range(len(nums)-1,i-1,-1):#对应第4步找到下标r,这里 r == j #然后交换 下标l 与 下标r 的值if nums[j] > nums[i-1]:nums[i-1],nums[j] = nums[j],nums[i-1]break# 对应第6步,反转下标l后的子序列for j in range((len(nums)-i+1)//2):nums[i+j],nums[len(nums)-1-j] = nums[len(nums)-1-j] ,nums[i+j]return numsnums.reverse()return nums

33.搜索旋转排序数组

class Solution:def search(self, nums: List[int], target: int) -> int:try:a = nums.index(target)return aexcept:return -1
#二分法
class Solution:def search(self, nums, target):left, right = 0, len(nums) - 1while left <= right:mid = (left + right) // 2if nums[mid] == target:return midelif nums[left] <= nums[mid]:if nums[left] <= target < nums[mid]:right = mid - 1else:left = mid + 1else:if nums[mid] < target <= nums[right]:left = mid + 1else:right = mid - 1return -1

34.在排序数组中查找元素的第一个和最后一个位置

class Solution:def combinationSum(self, candidates, target):candidates.sort()n = len(candidates)res = []def backtrack(i, tmp_sum, tmp):for j in range(i, n):# 如果和超过了target值,停止遍历,返回上层函数if tmp_sum + candidates[j] > target:break# 如果和等于target值,把结果添加进去,后面也没必要继续遍历了,停止遍历,返回上层函数if tmp_sum + candidates[j] == target:res.append(tmp + [candidates[j]])breakbacktrack(j, tmp_sum + candidates[j], tmp+[candidates[j]])backtrack(0, 0, [])return res

39.组合总和

在这里插入代码片

46.全排列

class Solution:def permute(self, nums: List[int]) -> List[List[int]]:res = []def backtrack(nums, tmp):if not nums:res.append(tmp)return for i in range(len(nums)):backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]])backtrack(nums, [])return res

48.旋转图像

class Solution:def rotate(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""pos1,pos2 = 0,len(matrix)-1while pos1<pos2:add = 0while add<pos2-pos1:#左上角(0,0),右下角(3,3)#左上角为0块,右上角为1块,右下角为2块,左下角为3块# temp = 3temp = matrix[pos2-add][pos1]# 3 = 2matrix[pos2-add][pos1] = matrix[pos2][pos2-add]# 2 = 1matrix[pos2][pos2-add] = matrix[pos1+add][pos2]# 1 = 0matrix[pos1+add][pos2] = matrix[pos1][pos1+add]# 0 = temp matrix[pos1][pos1+add] = tempadd += 1pos1 += 1pos2 -= 1

49.字母异位词分组

class Solution:def groupAnagrams(self, strs: List[str]) -> List[List[str]]:dic = {}for i in strs:key = "".join(sorted(i))if key not in dic:dic[key] = [i]else:dic[key].append(i)return list(dic.values())

55.跳跃游戏

class Solution:def canJump(self, nums: List[int]) -> bool:max_i = 0 #初始化当前能到达最远的位置for i, jump in enumerate(nums):#i为当前位置,jump是当前位置的跳数if max_i>=i and i+jump>max_i:  #如果当前位置能到达,并且当前位置+跳数>最远位置max_i = i+jump  #更新最远能到达位置return max_i>=i

56.合并区间

class Solution:def merge(self, intervals: List[List[int]]) -> List[List[int]]:intervals.sort()  #按首字母进行排序res = [intervals[0]]if not res: return []for x,y in intervals[1:]:if res[-1][1] < x:res.append([x,y])else:res[-1][1] = max(y,res[-1][1])return res

62.不同路径

class Solution:def uniquePaths(self, m: int, n: int) -> int:def dp(i,j):if 0 in (i,j):return 1return dp(i-1,j)+dp(i,j-1)#右下角=左边+上边return dp(m-1,n-1)#减1就是说明横纵能走几步
#n行mm列说明最终路径里面一定会有n-1n−1个向下的步骤和m-1m−1个向右的步骤。
#意思就是在m+n-2m+n−2个步骤的路径上,选n-1n−1个位置来向下走,剩下的位置向右走即可,这个数据量直接调函数即可。
class Solution:def uniquePaths(self, m: int, n: int) -> int:return  comb(m + n - 2, n - 1)

64.最小路径和

class Solution:def minPathSum(self, grid: List[List[int]]) -> int:for i in range(len(grid)):#行遍历for j in range(len(grid[0])): #列遍历if i==j==0:continueelif i==0:grid[i][j]=grid[i][j-1]+grid[i][j]elif j==0:grid[i][j]=grid[i-1][j]+grid[i][j]else:grid[i][j]=min(grid[i][j-1],grid[i-1][j])+grid[i][j]return grid[-1][-1]

75.颜色分类

class Solution:def sortColors(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""p=0 for i in range(len(nums)):if nums[i]==0:nums[i],nums[p]=nums[p],nums[i]p+=1for i in range(p,len(nums)):if nums[i]==1:nums[i],nums[p]=nums[p],nums[i]p+=1return nums

78.子集

class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:res = [[]]  for i in range(len(nums)):for sub in res[:]:res.append(sub+[nums[i]])return res

79.单词搜索

class Solution:def exist(self, board: List[List[str]], word: str) -> bool:row = len(board)col = len(board[0])def helper(i,j,k,visited):if k==len(word):return Truefor x,y in [(0,-1),(0,1),(-1,0),(1,0)]:#判断当前位置的上下左右的位置tempi = i + xtempj = j + yif 0<=tempi<row and 0<=tempj<col and board[tempi][tempj]==word[k] and (tempi,tempj) not in visited:visited.add((tempi,tempj))  #把符合的位置添加进去if helper(tempi,tempj,k+1,visited):return Truevisited.remove((tempi,tempj))#把上一个添加进去,但下一个不符合的移出来return False               for i in range(row):for j in range(col):if board[i][j]==word[0] and helper(i,j,1,{(i,j)}):return Truereturn False

96.不同的二叉搜索树

class Solution:def numTrees(self, n: int) -> int:# 假设n个节点存在二叉排序树的个数是G(n),令f(i)为以i为根的二叉搜索树的个数
# 即有:G(n) = f(1) + f(2) + f(3) + f(4) + ... + f(n)
# n为根节点,当i为根节点时,其左子树节点个数为[1,2,3,...,i-1],右子树节点个数为[i+1,i+2,...n],所以当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,即f(i) = G(i-1)*G(n-i),
# 上面两式可得:G(n) = G(0)*G(n-1)+G(1)*(n-2)+...+G(n-1)*G(0)dp = [0]*(n+1)#当为3时,[0,0,0,0]dp[0] = 1  #初始状态dp[1] = 1        for i in range(2,n+1):#  nfor j in range(1,i+1):dp[i]+=dp[j-1]*dp[i-j]return dp[n]

98.验证二叉搜索树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def isValidBST(self, root: TreeNode) -> bool:# 左子树的最大值**小于当前节点值,**右子树的最小值**大于当前节点值。而不是简单的左节点小于,右节点大于#二叉搜索树中序遍历为递增的顺序。(二叉搜索树的重要性质)res = []def helper(root):if not root:return helper(root.left)res.append(root.val)helper(root.right)helper(root)return res == sorted(res) and len(set(res)) == len(res)

102.二叉树的层序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = rightclass Solution:def levelOrder(self, root: TreeNode) -> List[List[int]]:#BFS+递归# if not root:#     return []# res = []# level = [root]# while level:#     tmp = []#     nextlevel = []#     for n in level:#         tmp.append(n.val)#         if n.left:#             nextlevel.append(n.left)#         if n.right:#             nextlevel.append(n.right)#     res.append(tmp)#     level = nextlevel# return res##BFS+回溯res = []def backtrack(root,depth):if not root:returnif len(res)==depth:res.append([])res[depth].append(root.val)backtrack(root.left,depth+1)backtrack(root.right,depth+1)backtrack(root,0)return res

105.从前序与中序遍历序列构造二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:if len(inorder)==0:return None#前序遍历第一个节点为根节点root = TreeNode(preorder[0])#因为没有重复元素,找到中序遍历中根节点的位置,左边是左子树,右边是右子树mid = inorder.index(preorder[0])#构建左子树root.left = self.buildTree(preorder[1:mid+1],inorder[:mid])root.right = self.buildTree(preorder[mid+1:],inorder[mid+1:])return root

114.二叉树展开为链表

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def flatten(self, root: TreeNode) -> None:"""Do not return anything, modify root in-place instead."""if not root or (not root.left and not root.right):return root#先把左右子树捋直self.flatten(root.left)self.flatten(root.right)tmp = root.right #把捋直的右子树备份一下root.right = root.left #把捋直的左子树放到右边root.left = None #记得把左子树置空while(root.right): #找到现在右子树的最后一个noderoot = root.rightroot.right = tmp #把捋直的原来的右子树接上去

128.最长连续序列

class Solution:def longestConsecutive(self, nums: List[int]) -> int:nums = set(nums)res = 0for num in nums:#判断第一个数字if num-1 not in nums:tmp = 1while num+1 in nums:num+=1tmp+=1res = max(tmp,res)return res#方法2
class Solution:def longestConsecutive(self, nums: List[int]) -> int:lookup = {}res = 0for num in nums:if num not in lookup:# 判断左右是否可以连起来left = lookup[num - 1] if num - 1 in lookup else 0right = lookup[num + 1] if num + 1 in lookup else 0# 记录长度lookup[num] = left + right + 1# 把头尾都设置为最长长度lookup[num - left] = left + right + 1lookup[num + right] = left + right + 1res = max(res, left + right + 1)return res

139.单词拆分

class Solution:def wordBreak(self, s: str, wordDict) -> bool:n = len(s)if not wordDict: return not sdp = [False] * (n + 1)dp[0] = Truefor i in range(1, n + 1):for j in range(i - 1, -1, -1):if dp[j] and s[j:i] in wordDict:  #从断的位置继续遍历下一个整体  宽度dp[i] = Truebreakreturn dp[-1]

142.环形链表2

环形解析
f=2s (快指针每次2步,路程刚好2倍)
f = s + nb (相遇时,刚好多走了n圈)
推出:s = nb
从head结点走到入环点需要走 : a + nb, 而slow已经走了nb,那么slow再走a步就是入环点了。
如何知道slow刚好走了a步? 从head开始,和slow指针一起走,相遇时刚好就是a步
1.第一次相遇,slow = nb
2.a+nb = 入口点
3.slow再走a = 入口 = head走到入口 = a
4.由3得出,起始距离入口 = 第一次相遇位置 + a
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = Noneclass Solution:def detectCycle(self, head: ListNode) -> ListNode:fast,slow = head,headwhile True:if not (fast and fast.next):returnfast,slow = fast.next.next,slow.nextif fast==slow:breakfast = headwhile fast != slow:fast,slow = fast.next,slow.nextreturn fast

146.LRU缓存

class ListNode:def __init__(self, key=None, value=None):self.key = keyself.value = valueself.prev = Noneself.next = Noneclass LRUCache:def __init__(self, capacity: int):self.capacity = capacityself.hashmap = {}# 新建两个节点 head 和 tailself.head = ListNode()self.tail = ListNode()# 初始化链表为 head <-> tailself.head.next = self.tailself.tail.prev = self.head# 因为get与put操作都可能需要将双向链表中的某个节点移到末尾,所以定义一个方法def move_node_to_tail(self, key):# 先将哈希表key指向的节点拎出来,为了简洁起名node#      hashmap[key]                               hashmap[key]#           |                                          |#           V              -->                         V# prev <-> node <-> next         pre <-> next   ...   nodenode = self.hashmap[key]node.prev.next = node.nextnode.next.prev = node.prev# 之后将node插入到尾节点前#                 hashmap[key]                 hashmap[key]#                      |                            |#                      V        -->                 V# prev <-> tail  ...  node                prev <-> node <-> tailnode.prev = self.tail.prevnode.next = self.tailself.tail.prev.next = nodeself.tail.prev = nodedef get(self, key: int) -> int:if key in self.hashmap:# 如果已经在链表中了久把它移到末尾(变成最新访问的)self.move_node_to_tail(key)res = self.hashmap.get(key, -1)if res == -1:return reselse:return res.valuedef put(self, key: int, value: int) -> None:if key in self.hashmap:# 如果key本身已经在哈希表中了就不需要在链表中加入新的节点# 但是需要更新字典该值对应节点的valueself.hashmap[key].value = value# 之后将该节点移到末尾self.move_node_to_tail(key)else:if len(self.hashmap) == self.capacity:# 去掉哈希表对应项self.hashmap.pop(self.head.next.key)# 去掉最久没有被访问过的节点,即头节点之后的节点 ,去除node这个结点self.head.next = self.head.next.nextself.head.next.prev = self.head# 如果不在的话就插入到尾节点前new = ListNode(key, value)self.hashmap[key] = newnew.prev = self.tail.prevnew.next = self.tailself.tail.prev.next = newself.tail.prev = new

148.排序链表(分治法)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:if not head or not head.next:return head fast = headslow = headwhile fast.next and fast.next.next:slow = slow.nextfast = fast.next.next#找到左右两部分,把左边的slow.next和右边的断开mid = slow.nextslow.next = None#递归下去,分到最小单位# 递归下去left = self.sortList(head)right = self.sortList(mid)# 合并return self.merge(left, right)def merge(self,left,right):#创建一个头结点h = ListNode(0)p = hwhile left and right:if left.val<right.val:p.next = leftleft = left.nextp = p.nextelse:p.next = rightright = right.nextp = p.nextif left:p.next = leftif right:p.next = rightreturn h.next              

152.乘积最大子数组

# 我们只要记录前i的最小值, 和最大值,
# 那么 dp[i] = max(nums[i] * pre_max, nums[i] * pre_min, nums[i]),
#这里0 不需要单独考虑, 因为当相乘不管最大值和最小值,都会置0
class Solution:def maxProduct(self, nums: List[int]) -> int:if not nums: returnres = nums[0]pre_max = nums[0]pre_min = nums[0]for num in nums[1:]:cur_max = max(pre_max * num, pre_min * num, num)cur_min = min(pre_max * num, pre_min * num, num)res = max(res, cur_max)pre_max = cur_maxpre_min = cur_minreturn res

198.打家劫舍

在这里插入代码片

200.岛屿数量

#DFS
#目标是找到矩阵中 “岛屿的数量” ,上下左右相连的 1 都被认为是连续岛屿。
# dfs方法: 设目前指针指向一个岛屿中的某一点 (i, j),寻找包括此点的岛屿边界。
# 从 (i, j) 向此点的上下左右 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 做深度搜索。
# 终止条件:
# (i, j) 越过矩阵边界;
# grid[i][j] == 0,代表此分支已越过岛屿边界。
# 搜索岛屿的同时,执行 grid[i][j] = '0',即将岛屿所有节点删除,以免之后重复搜索相同岛屿。
# 主循环:
# 遍历整个矩阵,当遇到 grid[i][j] == '1' 时,从此点开始做深度优先搜索 dfs,岛屿数 count + 1 且在深度优先搜索中删除此岛屿。
# 最终返回岛屿数 count 即可。
class Solution:def numIslands(self, grid: [[str]]) -> int:def dfs(grid, i, j):if not 0 <= i < len(grid) or not 0 <= j < len(grid[0]) or grid[i][j] == '0': returngrid[i][j] = '0'dfs(grid, i + 1, j)dfs(grid, i, j + 1)dfs(grid, i - 1, j)dfs(grid, i, j - 1)count = 0for i in range(len(grid)):for j in range(len(grid[0])):if grid[i][j] == '1':dfs(grid, i, j)count += 1return count

207.课程表

class Solution:def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:def dfs(i,behindclass,flags):if flags[i] == 1:return False  #说明已经遍历过了,不需要在访问了if flags[i] == -1:return True # flags[i] = 1
#只有这个标志位是干净的,别人还没有动过,我才能标记为1,说明本次dfs我遍历过它for j in behindclass[i]:#遍历当前课程下(理解为后边的)课程if not dfs(j,behindclass,flags): return Falseflags[i] = -1
#只有一次DFS完整结束了,才能执行到这一步,标记为-1,说明这条路没问题,再遇到不需要遍历了return Truebehindclass = [[] for _ in range(numCourses)] #几个格子上下对应flags = [0 for _ in range(numCourses)]  #先开始的课程的状态for cur, pre in prerequisites:# 把前后的课程放入behindclassbehindclass[pre].append(cur)   #把课程对应的分类for i in range(numCourses):if not dfs(i,behindclass,flags):return Falsereturn True

208实现Trie(前缀树)

class Trie:  #初始化前缀树对象def __init__(self):self.root = {}def insert(self, word: str) -> None: #插入tree = self.rootfor a in word:if not a in tree:tree[a] = {}tree = tree[a]tree["#"] = "#"def search(self, word: str) -> bool: #查找tree = self.rootfor a in word:if a not in tree:return Falsetree = tree[a]if "#" in tree:return True return Falsedef startsWith(self, prefix: str) -> bool:  #看前缀tree = self.rootfor a in prefix:if a not in tree:return Falsetree = tree[a]return  True# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

215.数组中的第K个最大元素

#基于快排的所有TopK问题简单python模板
def partition(nums, left, right):pivot = nums[left]#初始化一个待比较数据i,j = left, rightwhile(i < j):while(i<j and nums[j]>=pivot): #从后往前查找,直到找到一个比pivot更小的数j-=1nums[i] = nums[j] #将更小的数放入左边while(i<j and nums[i]<=pivot): #从前往后找,直到找到一个比pivot更大的数i+=1nums[j] = nums[i] #将更大的数放入右边#循环结束,i与j相等nums[i] = pivot #待比较数据放入最终位置 return i #返回待比较数据最终位置#快速排序
def quicksort(nums, left, right):if left < right:index = partition(nums, left, right)quicksort(nums, left, index-1)quicksort(nums, index+1, right)arr = [1,3,2,2,0]
quicksort(arr, 0, len(arr)-1)
print(arr)
def topk_split(nums, k, left, right):
#topk切分
#将快速排序改成快速选择,即我们希望寻找到一个位置,这个位置左边是k个比这个#位置上的数更小的数,右边是n-k个比该位置上的数大的数,我将它命名为#topk_split,找到这个位置后停止迭代,完成了一次划分。
#寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数if (left<right):index = partition(nums, left, right)if index==k:return elif index < k:topk_split(nums, k, index+1, right)else:topk_split(nums, k, left, index-1)
#接下来就依赖于上面这两个函数解决所有的topk问题
#获得前k小的数
#获得前k小的数
def topk_smalls(nums, k):topk_split(nums, k, 0, len(nums)-1)return nums[:k]arr = [1,3,2,3,0,-19]
k = 2
print(topk_smalls(arr, k))
print(arr)#获得第k小的数
def topk_small(nums, k):topk_split(nums, k, 0, len(nums)-1)return nums[k-1] #右边是开区间,需要-1arr = [1,3,2,3,0,-19]
k = 3
print(topk_small(arr, k))
print(arr)
#获得前k大的数
def topk_larges(nums, k):#parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数topk_split(nums, len(nums)-k, 0, len(nums)-1) #把k换成len(nums)-kreturn nums[len(nums)-k:] arr = [1,3,-2,3,0,-19]
k = 3
print(topk_larges(arr, k))
print(arr)
#获得第k大的数
def topk_large(nums, k):#parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数topk_split(nums, len(nums)-k, 0, len(nums)-1) #把k换成len(nums)-kreturn nums[len(nums)-k] arr = [1,3,-2,3,0,-19]
k = 2
print(topk_large(arr, k))
print(arr)
#只排序前k个小的数
#获得前k小的数O(n),进行快排O(klogk)
def topk_sort_left(nums, k):topk_split(nums, k, 0, len(nums)-1) topk = nums[:k]quicksort(topk, 0, len(topk)-1)return topk+nums[k:] #只排序前k个数字arr = [0,0,1,3,4,5,0,7,6,7]
k = 4
topk_sort_left(arr, k)
#只排序后k个大的数
#获得前n-k小的数O(n),进行快排O(klogk)
def topk_sort_right(nums, k):topk_split(nums, len(nums)-k, 0, len(nums)-1) topk = nums[len(nums)-k:]quicksort(topk, 0, len(topk)-1)return nums[:len(nums)-k]+topk #只排序后k个数字arr = [0,0,1,3,4,5,0,-7,6,7]
k = 4
print(topk_sort_right(arr, k))

221.最大正方形

class Solution:def maximalSquare(self, matrix: List[List[str]]) -> int:row = len(matrix)col = len(matrix[0])max_side = 0dp = [[0]*(col+1) for _ in range(row+1)]for i in range(row):for j in range(col):if matrix[i][j]=="1":dp[i+1][j+1] = min(dp[i][j],dp[i+1][j],dp[i][j+1])+1max_side = max(max_side,dp[i+1][j+1])return max_side*max_side

236.二叉树的最近公共祖先

class Solution:def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':if not root:return None# 边界条件,如果匹配到left或right就直接返回停止递归if root.val == p.val or root.val == q.val:return root# 这两行代码可以无脑先写好!# 因为是DFS算法,这个模板可以无脑套用,写上之后可能你思路就清晰很多left = self.lowestCommonAncestor(root.left,p,q)right = self.lowestCommonAncestor(root.right,p,q)# 如果既在左子树找到,又在右子树找到,那么毫无疑问当前root就是公共节点if left and right:return root# 只有左子树有,那么直接返回左子树匹配到的第一个节点if left:return leftif right:return right

238.除自身以外数组的乘积

class Solution:def productExceptSelf(self, nums: List[int]) -> 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*1res,p,q = [1],1,1for i in range(len(nums)-1):  #先把左半部分给算出来p *= nums[i]res.append(p)for j in range(len(nums)-1,0,-1):#再从右边儿倒着过来乘起来q *= nums[j]res[j-1] *= qreturn res

240.搜索二维矩阵2

class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:#bfs的思路是按照一行一行的去遍历的,可以使右上角也可以是左下角#按照右上角写m,n = len(matrix),len(matrix[0])  i,j = 0,n-1while i<m and j>=0:if matrix[i][j]==target:return Trueelif matrix[i][j]>target:j -= 1else:i += 1return False

279.完全平方数

class Solution:def numSquares(self, n: int) -> int:# 组成和的完全平方数的最多个数,就是只用1构成# 因此,dp[i] = idp = [i for i in range(n+1)]# dp[0] = 0 无意义,只是为了方便记录特殊情况:# n本身就是完全平方数,dp[n] = min(dp[n], dp[n - n] + 1) = 1for i in range(1,n):#遍历物品if i*i>n:breaknum = i*ifor j in range(num,n+1):#遍历背包dp[j] = min(dp[j],dp[j-num]+1)return dp[n]

标题287.寻找重复数

class Solution:def findDuplicate(self, nums: List[int]) -> int:
#         f=2s (快指针每次2步,路程刚好2倍)
# f = s + nb (相遇时,刚好多走了n圈)
# 推出:s = nb
# 从head结点走到入环点需要走 : a + nb, 而slow已经走了nb,那么slow再走a步就是入环点了。
# 如何知道slow刚好走了a步? 从head开始,和slow指针一起走,相遇时刚好就是a步
# 1.第一次相遇,slow = nb
# 2.a+nb = 入口点
# 3.slow再走a = 入口 = head走到入口 = a
# 4.由3得出,起始距离入口 = 第一次相遇位置 + afast,slow = 0,0while True:slow = nums[slow]fast = nums[nums[fast]]if slow==fast:breakfind = 0while True:find = nums[find]slow = nums[slow]if slow==find:return find

300.最长递归子序列

class Solution:def lengthOfLIS(self, nums: List[int]) -> int:#用动态规划,设置一个同步的组,然后挨个遍历,之前的状态不变,变得话从之前最大的状态加1if not nums:return 0dp = [1]*len(nums)for i in range(len(nums)):for j in range(i):if nums[j]<nums[i]:  #如果不是强点单调递增,有相等的情况,可以写成<=dp[i] = max(dp[i],dp[j]+1)return max(dp)

309.最佳买卖股票时机含冷冻期

class Solution:def maxProfit(self, prices: List[int]) -> int:if len(prices)<2: return 0dp0=0  # 手里没股票,没有处于冷冻期dp1=float("-inf")  # 手里没股票,并且处于冷冻期dp2=- prices[0]  # 手里有股票for i in range(1, len(prices)):new_dp0=max(dp0, dp1)  #前一天是dp0/dp1(手里都没有股票,非冷冻期/冷冻期),今天变成dp0(手里没有股票,非冷冻期)new_dp1=dp2+prices[i]   #前一天的卖出,今天变成没有股票的冷冻期new_dp2=max(dp2, dp0-prices[i])  #前一天是dp2(没有股票的冷冻期)/前一天解冻完后买入的dp0dp0, dp1, dp2=new_dp0, new_dp1, new_dp2return max(dp0, dp1)

322.零钱兑换

背包问题:
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。

# dp[j]代表含义:填满容量为j的背包最少需要多少硬币
# 初始化dp数组:因为硬币的数量一定不会超过amount,而amount <= 10^4
#  ,因此初始化数组值为10001;dp[0] = 0
# 转移方程:dp[j] = min(dp[j], dp[j - coin] + 1)
# 当前填满容量j最少需要的硬币 = min( 之前填满容量j最少需要的硬币, 填满容量 j - coin 需要的硬币 + 1个当前硬币)
# 返回dp[amount],如果dp[amount]的值为10001没有变过,说明找不到硬币组合,返回-1
coins = [1, 2, 5]
amount = 11
class Solution:def coinChange(self, coins, amount):dp = [0] + [10001] * amountfor coin in coins:for j in range(coin, amount + 1):dp[j] = min(dp[j], dp[j - coin] + 1)return dp[-1] if dp[-1] != 10001 else -1
a = Solution()
print(a.coinChange(coins,amount))

337.打家劫舍3

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def rob(self, root: TreeNode) -> int:def _rob(root):if not root: return 0, 0  # 偷,不偷left = _rob(root.left)right = _rob(root.right)# 偷当前节点, 则左右子树都不能偷v1 = root.val + left[1] + right[1] #left的第二个返回值,也就是不偷left的值# 不偷当前节点, 则取左右子树中最大的值v2 = max(left) + max(right)return v1, v2  #这个节点偷和不偷的受益同时返回。return max(_rob(root))

347.前k个高频元素

# Counter 是一个在collections包里的类,正如其名,是一个用于计数的工具。
# 我们可以用Counter(nums)这样的构造函数构造一个Counter类,其中nums是一个列表。
# 构造好的Counter实例可以看作一个字典,键是nums的每一项,值是它的出现次数。
# 如果上面的叙述让你感到很混乱的话,我不妨举个例子。
# 如果一个列表a = [1,1,3,4,3],你想要统计每项的出现次数,那么你使用b = Counter(a),那么这时候b就像一个这样的字典{1:2,3:2,4:1},表示数字1出现了2次,数字3出现了2次,数字4出现了1次。
# 还是很好理解的吧?
# 可是题目里要我们输出的是最多的K项
# 这时候可以应用Counter的一个函数,most_common(k)
# 这个函数就是返回最多出现的K项
# 但是返回的形式是一个元祖列表,类似[(1,2),(3,2),(4,1)]的形式
# 我们只需要键也就是第一项,所以要使用列表生成式处理一下即可。count = collections.Counter(nums)return [item[0] for item in count.most_common(k)]

leecode100题(自用)相关推荐

  1. 408 | 【2014年】计算机统考真题 自用回顾知识点整理

    选择题 T3:循环队列 不同指针指向,队列判空/判满条件 1. rear:指向队尾元素 front:指向队头元素前一个位置     (1)牺牲一个存储空间     (2)判空条件:front == r ...

  2. 高数 | 周洋鑫 冲刺预测题自用整理复习

    自用笔记整理复习. 内容来自2023周洋鑫冲刺班. 加油ヾ(◍°∇°◍)ノ゙ 1.函数极限计算 [加项减项] ☆ 二次积分求极限 [分母与面积同阶]-- 走二重积分中值定理 ☆ 中值点的包装 学思想 ...

  3. 408 | 【2010年】计算机统考真题 自用回顾知识点整理

    选择题 T3:线索二叉树 T9:查找算法比较次数 -- 折半查找 仅适用于有序顺序表 顺序存储结构 计算ASL时,自己推,圆形结点n个,方块结点n+1个(失败) 判定树是一棵平衡二叉树 判定树高度 ⌊ ...

  4. 408 | 王道模拟冲刺题自用笔记整理(第二套)

    T5:森林与二叉树的转换 特殊二叉树.二叉树的性质 高度为h的满二叉树,对应森林的树的个数一定为h. T7:平衡二叉树的性质 T8:图的存储结构

  5. 剑指offer.01 数组中重复的数(0504刷题自用)

    代码 class Solution {public:int findRepeatNumber(vector<int>& nums) {unordered_map <int,i ...

  6. 高数 |【2020数一真题】部分错题及经典题自用思路整理

    T1:积分限与被积函数都等价为无穷小 T2:不连续一定不可导 T3:可微的定义 T4:收敛半径 T6:空间直线与向量 法一:

  7. 高数 |【2021数一真题】部分错题及经典题自用思路整理

    T2:对 1.2 位置求导 T3:泰勒展开的唯一性 首先可观察到奇偶性,排除CD 法一:套公式 法二:乘积 法三:极限 T4:定积分(分割࿰

  8. Python编程题自用(一)

    统计python源代码文件中,代码行数,去除注释,空行,进行输出? """ 解题思路: 打开文件并读取文件,readlines()方法一次性读取整个文件,并自动将内容分析 ...

  9. Taro-ui 常用 UI 组件库说明

    Taro-ui 常用 UI 组件库说明 https://taro-ui.jd.com/#/docs/introduction 安装 npm install -g @tarojs/cli taro in ...

最新文章

  1. Linux centos下项目环境搭建及版本部署
  2. libevent多线程
  3. hdu 3007【爬山算法】
  4. 前、中、后缀表达式概述及转换+栈的计算器原理及代码分析(含完整源码)
  5. 【地狱副本】数据结构之线段树Ⅲ——区间最值/赋值/修改/历史值操作(HDU5306,Tyvj 1518,【清华集训2015】V,HDU6315,HDU1828,POJ3162)
  6. leetcode(动态规划专题)
  7. DDD~DDD从零起步架构说明
  8. Python的正则匹配
  9. linux下如何创建oracle数据库实例,Linux下新建Oracle数据库实例
  10. 勤于奋:国外LEAD跟联盟经理沟通聊天软件,Skype注册教程
  11. 自定义锁屏图片 win7
  12. 泛型和容器--2--容器
  13. win10防火墙打不开,设置是灰色的、edge闪退、应用商店灰色等问题
  14. 创业公司如何搭建服务器配置方案?
  15. 无Internet,安全的解决方法
  16. 站在数字经济浪尖:360视觉云探路中小微企业数智转型
  17. 对睡眠好的东西,失眠了,就看看这些助眠好物
  18. 期刊分类—CSSCI、A类、B类、C类、核心期刊的区别
  19. python判断邮件发送成功_【基本解决】python中用SMTP发送QQ邮件提示成功但是收件人收不到邮件...
  20. linux基本命令练习

热门文章

  1. 21岁拿遍全世界编程大赛冠军
  2. FCPX插件 图标和徽标动画 CineFlare KineticBadges v1.0.3破解版
  3. 读博阶段需要注意的几个问题
  4. About 7.17 This Week
  5. 度量体系建立与COSMIC方法应用36问
  6. 将EMF文件转换成JPG文件
  7. html 记录点击次数,jquery/js记录点击事件,单击次数加一,双击清零
  8. 随便唠唠 编译时注解 这个技术
  9. 联通TEWA 800改桥接
  10. mysql 国密_Centos7 编译安装 Openssl 1.1.1 支持国密标准-1002682