leetcode整理

一、数组

1. 二分法

第35题 搜索插入位置
第34题 在排序数组中查找元素的第一个和最后一个位置
第69题 x 的平方根
第367题 有效的完全平方数
第704题 二分查找

2. 双指针

#移动元素、移动0
#右指针j将一直指向不等于val值(0 or target)的值
i = 0
for j in range(len(nums)):
	if nums[j]!=val:
		nums[i],nums[j] = nums[j],nums[i]
	i+=1
#输出更新后序列的长度
print(i)

第27题 移除元素
第26题 删除排序数组中的重复项
第283题 移动零
第844题 比较含退格的字符串
第977题 有序数组的平方

3. 滑动窗口

第209题 长度最小的子数组
第904题 水果成篮
第76题 最小覆盖子串

4. 螺旋矩阵(循环边界条件)

第59题 螺旋矩阵II
第54题 螺旋矩阵
剑指Offer 29.顺时针打印矩阵

二、链表

1. 删除、插入、获取值

第707题 设计链表
第237题 删除链表中的节点

2. 反转链表

第206题 反转链表
第92题 反转链表 II
第234题 回文链表

3. 删除倒数节点

第19题 删除链表的倒数第N个节点

4. 链表相交

面试题 02.07. 链表相交

5. 环链表

第142题 环形链表II

6. 排序链表

第148题 排序链表
第143题 重排链表

其他

第114题 二叉树展开为链表

三、哈希表

1. 数组哈希表(ord(‘a’)-ord(‘z’))

只包含26个字母时使用
第242题 有效的字母异位词
第383题 赎金信

2. set集合

第349题. 两个数组的交集
第202题 快乐数

3. map

第1题. 两数之和
第454题.四数相加II

4. 双指针

第15题. 三数之和
第18题. 四数之和

四、字符串

1. 反转字符串

第344题 反转字符串 ,库函数reverse()
第541题 反转字符串II ,range使用
第151题 翻转字符串里的单词 ,全局→局部
剑指Offer58-II.左旋转字符串

2. KMP算法

KMP求next数组中,i指向后缀末尾,j指向前缀末尾,j也代表最大公共前缀的长度
第28题 实现 strStr()
next数组最后一位是最大公共前后缀长度,
条件1:长度能被整除
条件2:k个该公共前后缀能组成原数组
第459题 重复的子字符串

3. OrderedDict

第146题 LRU缓存机制

五、栈与队列

第20题 有效的括号
第1047题 删除字符串中的所有相邻重复项
第150题 逆波兰表达式求值
第71题 简化路径(经典题)

1.互转

第232题 用栈实现队列, 两个栈来实现
第225题 用队列实现栈

2. 单调队列

第239题 滑动窗口最大值

3. 优先级队列(堆)

第347题 前 K 个高频元素 , 也可以用collections.Count()和排序做

4.单调栈

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈
第739题 每日温度
第496题 下一个更大元素 I
第503题 下一个更大元素 II
第901题 股票价格跨度
第402题 移掉 K 位数字
第581题 最短无序连续子数组
第42题 接雨水
第84题 柱状图中最大的矩形
第316题 去除重复字母

六、二叉树

1. 二叉树的遍历方式

前序遍历
中序遍历
后序遍历
第102题 层序遍历
第103题 二叉树的锯齿形层序遍历

2. 求二叉树的属性

(1)是否对称

第101题 对称二叉树(dfs传入左右子树)

(2)求深度

第104题 二叉树的最大深度
第559题 N叉树的最大深度
第111题 二叉树的最小深度
第543题 二叉树的直径

(3)求最小节点数

第222题 完全二叉树的节点个数

(4)是否平衡

第110题 平衡二叉树

(5)找所有路径

第257题 二叉树的所有路径

(6)递归&回溯

第100题 相同的树
剑指 Offer 26. 树的子结构
第257题 二叉树的所有路径

(7)求叶子和、值

第404题 左叶子之和
第513题 找树左下角的值

(8)求路径和

第112题 路径总和
第113题 路径总和II

3. 二叉树的修改与构造

第226题 翻转二叉树

#构造一般从前序后序找到root.val,从中序找到left和right的分界线:inorder.index(root.val)
#前序遍历[head|left|right]
#中序遍历[left|head|right]
#后序遍历[left|right|head]

第106题 从中序与后序遍历序列构造二叉树
第105题 从前序与中序遍历序列构造二叉树
第654题 最大二叉树
第617题 合并二叉树

4. 二叉树公共祖先问题

第236题 二叉树的最近公共祖先
第235题 二叉搜索树的最近公共祖先

5. 二叉搜索树(BST)的修改与构造

第701题 二叉搜索树中的插入操作
第450题 删除二叉搜索树中的节点
第669题 修剪二叉搜索树
第108题 将有序数组转换为二叉搜索树
第538题 把二叉搜索树转换为累加树

七、回溯

回溯算法解决的问题:
组合问题:N个数里面按一定规则找出k个数的集合
排列问题:N个数按一定规则全排列,有几种排列方式
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
棋盘问题:N皇后,解数独等等

1. 组合

## 排列组合问题经典模板
res = []
path = []
#函数传递index
def backtrack(index):
	if len(path) == k:
		res.append(path[:])
            return 
        # n-(k-len(path))+2剪枝,去除后续长度不能满足组合总长的数字
        for i in range(index,n-(k-len(path))+2):
            path.append(i)
            backtrack(i+1)
            path.pop()
backtrack(1)
print(res)
## 组合总和(target)问题
res = []
path = []
candidates.sort()
#函数传递新的nums和target
# 1.可重复使用nums中的数字
def backtrack(nums,target):
	if target == 0:
		res.append(path[:])
		return  
	for i,num in enumerate(nums):
		if num > target:
			break
		path.append(num)
		backtrack(nums[i:],target-num)
		path.pop()
# 2.不可重复使用nums中的数字
def backtrack(nums,target):
	if target == 0:
		res.append(path[:])
		return  
	for i,num in enumerate(nums):
		if num > target:break
		if i!=0 and nums[i] == nums[i-1]:continue
		path.append(num)
		backtrack(nums[i+1:],target-num)
		path.pop()
#运行回溯函数并打印结果
backtrack(nums,target)
print(res)

第77题 组合
第216题 组合总和III
第17题 电话号码的字母组合
第39题 组合总和
第40题 组合总和II

2.切割

## 切割问题维护一个lenth,当列表内的所有子串总长度lenth与总串长度n相等时,将该列表添加到总答案中
#切割问题的回溯函数传递参数均为指针位置index和子串总长lenth
res = []
path = []
n = len(s)
## 无分割长度要求
def backtrack(index,lenth):
	if lenth == n:
		res.append(path[:])
	for i in range(index,n):
		 = s[index:i+1]
		if ss == ss[::-1]:
			path.append(ss)
		backtrack(i+1,lenth+len(child))
		path.pop()
## 有分割长度要求(每段有数值要求和长度要求)
def backtrack(index,lenth):
	if len(path) == 4:
		if lenth == n:
			res.append('.'.join(path[:]))
		return
	for i in range(index,min(index+4,len(s))):
		ss = s[index:i+1]
		if 0 <= int(ss) <= 255 and str(int(ss)) == ss:
			path.append(ss)
			backtrack(i+1,lenth+len(ss))
			path.pop()
backtrack(0,0)
print(res) 

第131题 分割回文串
第93题 复原IP地址

3.子集

## 子集问题回溯函数传递的参数均为指针位置index
res = []
path = []
# 数组内各数字各不相同
def backtrack(index):
	res.append(path[:])
	for i in range(index,len(nums)):
		path.append(nums[i])
		backtrack(i+1)
		path.pop()
# 数组内包含重复数字,解集内不能包含重复答案
nums.sort()
def backtrack(index):
	res.append(path[:])
	used = set()
	for i in range(index,len(nums)):
		if nums[i] in used:continue
		used.add(nums[i])
		path.append(nums[i])
		backtrack(i+1)
		path.pop()
#求数组中子序列的问题(避免重复加入同一个后缀)
def backtrack(index):
	if len(path)>1:
		res.append(path[:]) 
	used = set()
	for i in range(index,n):
		if nums[i] in used:continue
		if not path or nums[i]>=path[-1]:
			used.add(nums[i])
			path.append(nums[i])
			backtrack(i+1)
			path.pop()
#输出答案
backtrack(0)
print(res)

第78题 子集
第90题 子集II
第491题 递增子序列

4.排列

## 数组所有排列问题模板
res = []
path = []
# 数组内不含重复元素
def backtrack(nums):
	if not nums:
		res.append(path[:])
	for i in range(len(nums)):
		path.append(nums[i])
		backtrack(nums[:i]+nums[i+1:])
		path.pop()
# 数组内包含重复元素
def backtrack(nums):
	if not nums:
		res.append(path[:])
	used = set()
	for i in range(len(nums)):
		if nums[i] in used:continue
		used.add(nums[i])
		path.append(nums[i])
		backtrack(nums[:i] + nums[i+1:])
		path.pop()
#输出答案
backtrack(nums)
print(res)

第46题 全排列
第47题 全排列II
剑指 Offer 38. 字符串的排列

5.棋盘问题

第51题 N皇后 (使用set会更加快捷)
第37题 解数独

岛屿(DFS)

(先导题,不需要回溯:463题 岛屿的周长)
第200题 岛屿数量(求数量时每经过一个岛的位置将删去这个岛)
第695题 岛屿的最大面积(求面积累加当前位置的单位1面积和周围4个位置的面积)
第827题 最大人工岛(2次dfs,(1)记录每个岛的面积,(2)面积相加)

6.其他

第332题重新安排行程
剑指 Offer 34. 二叉树中和为某一值的路径
剑指 Offer 12. 矩阵中的路径
第95题 不同的二叉搜索树 II

堆(优先队列)

heappush(heap, x) 将x压入堆中
heappop(heap) 从堆中弹出最小的元素
heapify(heap) 让列表具备堆特征
heapreplace(heap, x) 弹出最小的元素,并将x压入堆中
nlargest(n, iter) 返回iter中n个最大的元素
nsmallest(n, iter) 返回iter中n个最小的元素

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

八、动态规划

第509题 斐波那契数
第70题 爬楼梯
第746题 使用最小花费爬楼梯
第62题 不同路径
第63题 不同路径II
第96题 不同的二叉搜索树

1. 01背包问题

(1)能否装满背包(或者最多装多少)

dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
第416题 分割等和子集
第1049题 最后一块石头的重量II

(2)装满背包有几种方法

dp[j] += dp[j - nums[i]]
第494题 目标和

(+377)

(3)背包装满最大价值

dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
第474题 一和零

2. 完全背包问题

1.如果求组合数就是外层for循环遍历物品,内层for遍历背包。
2.如果求排列数就是外层for遍历背包,内层for循环遍历物品(物品放入背包的时候存在顺序关系)
第518题 零钱兑换II ······1 求组合数
第322题 零钱兑换 ······1 求最小数
第377题 组合总和 Ⅳ ······2 求排列数
第279题 完全平方数 ······1 求最小数
第139题 单词拆分 ······2

(1)问装满背包所有物品的最小个数

dp[j] = min(dp[j - coins[i]] + 1, dp[j])
(+322,+279)

3.打家劫舍

第198题打家劫舍
第213题 打家劫舍II
第337题 打家劫舍III

4.股票买卖

## 做多可以买卖k次(限定交易次数的通用写法)
dp = [[0]*2*k for _ in range(len(prices))]
for j in range(0,2*k,2):dp[0][j] = -prices[0] #初始化第一次交易状态
for i in range(1,len(prices)):
	for j in range(2*k):
		#第一次买入max(买 or 不买)
		if j == 0:
			dp[i][j] = max(-prices[i], dp[i-1][j])
		#第k次买入max(买 or 不买)
		elif j % 2 == 0:
			dp[i][j] = max(-prices[i] + dp[i-1][j-1], dp[i-1][j])
		#第k次卖出max(卖 or 不卖)
		elif j%2 == 1:
			dp[i][j] = max(prices[i] + dp[i-1][j-1], dp[i-1][j])
			
## 只能买卖一次
dp = [[0]*2 for _ in range(len(prices))]
dp[0][0] = -prices[0]
for i in range(1,len(prices)):
	dp[i][0] = max(-prices[i], dp[i-1][0])
	dp[i][1] = max(prices[i] + dp[i-1][0], dp[i-1][1])
	
## 可以买卖无限次
dp = [[0]*2 for _ in range(len(prices))]
dp[0][0] = -prices[0]
for i in range(1,len(prices)):
	dp[i][0] = max(-prices[i]+ dp[i-1][1], dp[i-1][0])
	dp[i][1] = max(prices[i] + dp[i-1][0], dp[i-1][1])

## 含冷冻期(买入、卖出、冷冻期、买入、卖出)
# 冷冻期后买入的收益与前第二天相关,所以需要初始化前两天的状态
dp = [[0]*2 for _ in range(len(prices))]
dp[0][0] = -prices[0]
dp[1][0] = max(-prices[1], dp[0][0])
dp[1][1] = prices[1] - dp[0][0]
for i in range(1,len(prices)):
	dp[i][0] = max(-prices[i] + dp[i-2][1], dp[i-1][0])
	dp[i][1] = max(prices[i] + dp[i-1][0], dp[i-1][1])

第121题 买卖股票的最佳时机
第122题 买卖股票的最佳时机II
第123题 买卖股票的最佳时机III
第188题 买卖股票的最佳时机IV
第309题 最佳买卖股票时机含冷冻期
第714题 买卖股票的最佳时机含手续费

5.子序列

(1)比较当前数字和上一个数字,维护变量maxlen

## 求递增
if condition == True:
	dp[i] = max(dp[i],dp[j]+1)
	dp[i] = dp[i-1]+1
	
## 求最大和
dp[i] = max(nums[i]+dp[i-1],nums[i])

第300题 最长递增子序列
第674题 最长连续递增序列
第53题 最大子序和

(2)判断i-1,j-1位置数字 or 字符串是否相等

## 子数组(连续)
# dp[i][j]的意义是两个数组i和j位置前的子数组的联合状态
# 维护res,状态转移条件为i,j位置前置子数组末尾的两个字符是否相等
dp = [[0]*n for _ in range(m)]
for i in range(1,m):
    for j in range(1,n):
        if nums1[i-1] == nums2[j-1]:
            dp[i][j] =dp[i-1][j-1] + 1 
            
## 子序列(不连续)
# 由于子序列不连续,i和j位置前的子串的公共子序列的状态dp[i][j]更新条件为:
# 如果i-1 j-1位置的字符相同,更新为上一位置的公共长度+1
# 不同,则继承i,j-1 和i-1,j两个相邻状态中的最大值
dp = [[0]*n for _ in range(m)]
for i in range(1,m):
	for j in range(1,n):
		if text1[i-1] == text2[j-1]:
			dp[i][j] = dp[i-1][j-1] + 1 
		else:
			dp[i][j] = max(dp[i][j-1],dp[i-1][j])
## 删除操作
 dp = [[0]*n for _ in range(m)]
 for i in range(m):dp[i][0] = i
 for j in range(n):dp[0][j] = j
 for i in range(1,m):
     for j in range(1,n):
         if word1[i-1] == word2[j-1]:
             dp[i][j] = dp[i-1][j-1]
         else:
             dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1
  

第718题 最长重复子数组
第1143题 最长公共子序列
第1035题 不相交的线(与1143思路一致)
第392题 判断子序列(可用双指针)
第115题 不同的子序列(比较特殊)
第583题 两个字符串的删除操作
第72题 编辑距离(思路同583)
第647题 回文子串(倒序遍历左指针)
第516题 最长回文子序列
美团笔试题:回文串构建
题目描述:
小美现在有一个字符串,小美现在想知道能不能通过字符串在尾部增加若干字符使得整个字符串变成一个回文串。
对于字符串abaaca,在该字符串末尾补上三个字符aba就可以构成abaacaba是一个回文串。
你的任务是找到使得原来的字符串变成回文串所需要的最少字符数量。
*本题输入不包含空串,因此不考虑空串是否为回文串
解:

def addlenth(text):
	n = len(text)
	dp = [[0]*n for _ in range(n)]
	res = 0
	#思路同力扣516题,但求的是以i∈(0,len(text))开头,j = len(text)结尾的最长回文串
	#i为字符串起始位置指针,j为字符串末尾位置指针
	for i in range(n-1,-1,-1):
		for j in range(i,n):
			if text[i] == text[j]:
				if i == j:
					dp[i][j] = 1
				else:
				#若i,j指针处的字符相等,则该位置的回文串长度为内部最长回文串长+2
					dp[i][j] = dp[i+1][j-1] + 2
	#求以i∈(0,len(text))开头,j = len(text)结尾的最长回文串,求dp[:,-1]中的最大值
	for i in range(n):
		if res< dp[i][-1]: 
			res = dp[i][-1]
	#补充字符串的长度等于总长n-最长回文串长度res
	return n-res

if __name__ == '__main__':
    text = 'abbbbbac'
    print(addlenth(text))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值