目录
6、是否存在叶子节点到根节点总和对应输入的数字 num112
9、给定一个 没有重复 数字的序列,返回其所有可能的全排列。(回溯)
2、计算一组字符集合可以组成的回文字符串的最大长度(统计每个字符出现次数)
4、判断一个整数是否是回文数(转成字符双指针或者求回文的数)
5、统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
5、一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数
6、(二分)找出数组中重复的数,数组值在 [1, n] 之间(要求不能修改数组,也不能使用额外的空间。)
9、S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i],指导首尾相等
10: 统计从 0 ~ n 每个数的二进制表示中 1 的个数
一:动态规划
1. 爬楼梯
import numpy as np
class Solution:
def climbStairs(self, n: int) -> int:
res=np.zeros(n+1,np.int)
res[0],res[1]=1,1
for i in range(2,n+1):
res[i] = res[i - 1] + res[i - 2]
return int(res[n])
2.强盗抢劫
题目描述:抢劫一排住户,但是不能抢邻近的住户,求最大抢劫量。定义 dp 数组用来存储最大的抢劫量,其中 dp[i] 表示抢到第 i 个住户时的最大抢劫量。由于不能抢劫邻近住户,如果抢劫了第 i -1 个住户,那么就不能再抢劫第 i 个住户,所以
import numpy as np
import math
class Solution:
#初始化比较麻烦 dp[0]=nums[0] dp[1]=max(nums[0],nums[1])
#递推公式 dp[i]=max(dp[i-1],dp[i-2]+nums[i])
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
if(len(nums)==1):
return nums[0]
dp=np.zeros(len(nums)+1,np.int)
dp[0]=nums[0]
dp[1]=max(nums[0],nums[1])
for index in range(2,len(nums)):
dp[index]=max(dp[index-1],dp[index-2]+nums[index])
return int(dp[len(nums)-1])
3.强盗在环形街区抢劫
这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
import numpy
class Solution:
def rob(self, nums: List[int]) -> int:
#一个是从0到n-1,另一个是从1到n
if not nums:
return 0
if(len(nums)==1):
return nums[0]
if(len(nums)==2):
return max(nums[0],nums[1])
dp1,dp2=numpy.zeros(len(nums),numpy.int),numpy.zeros(len(nums),numpy.int)
dp1[0]=nums[0]
dp1[1]=max(nums[1],nums[0])
for index1 in range(2,len(nums)-1):
dp1[index1]=max(dp1[index1-1],dp1[index1-2]+nums[index1])
nums2=nums[1:]
dp2[0]=nums2[0]
dp2[1]=max(nums2[0],nums2[1])
for index2 in range(2,len(nums)-1):
dp2[index2]=max(dp2[index2-1],dp2[index2-2]+nums2[index2])
return int(max(dp1[len(nums)-2],dp2[len(nums)-2]))
4.最短路径的和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
import numpy as np
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
#初始化 dp[0][0] = grid[0][0];
#第一行第一列均为之前求和
#dp[row][col]=min(dp[row-1][col],dp[row][col-1])+grid[row][col]
rows=len(grid)
cols=len(grid[0])
dp=np.zeros((rows,cols),dtype=np.int32)
dp[0][0] = grid[0][0];
for row in range(1,rows):
dp[row][0]=dp[row-1][0]+grid[row][0]
for col in range(1,cols):
dp[0][col]=dp[0][col-1]+grid[0][col]
for row in range(1,rows):
for col in range(1,cols):
dp[row][col]=min(dp[row-1][col],dp[row][col-1])+grid[row][col]
return int(dp[rows-1][cols-1])
5.矩阵的总路径数
import numpy as np
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
#初始状态第一行第一列全是1
#dp[i][j]=dp[i-1][j]+dp[i][j-1]
dp=np.zeros((m,n),np.int32)
for i in range(m):
for j in range(n):
if(i==0 or j==0):
dp[i][j]=1
for i in range(1,m):
for j in range(1,n):
dp[i][j]=dp[i-1][j]+dp[i][j-1]
return int(dp[m-1][n-1])
6:数组中等差递增子区间的个数
如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q),P 与 Q 是整数且满足 0<=P<Q<N 。如果满足以下条件,则称子数组(P, Q)为等差数组:元素 A[P], A[p + 1], ..., A[Q - 1], A[Q] 是等差的。并且 P + 1 < Q 。函数要返回数组 A 中所有为等差数组的子数组个数。
import numpy as np
class Solution:
def numberOfArithmeticSlices(self, A: List[int]) -> int:
#dp[i] 表示以 A[i] 为结尾的等差递增子区间的个数。
# dp[2] = 1
# [0, 1, 2]
# dp[3] = dp[2] + 1 = 2
# [0, 1, 2, 3], // [0, 1, 2] 之后加一个 3
# [1, 2, 3] // 新的递增子区间
# dp[4] = dp[3] + 1 = 3
# [0, 1, 2, 3, 4], // [0, 1, 2, 3] 之后加一个 4
# [1, 2, 3, 4], // [1, 2, 3] 之后加一个 4
# [2, 3, 4] // 新的递增子区间
if not A or len(A)<=2:
return 0
dp=np.zeros(len(A),np.int)
dp[0],dp[1]=0,0
for i in range(2,len(A)):
if(A[i]-A[i-1]==A[i-1]-A[i-2]):
dp[i]=dp[i-1]+1
return int(sum(dp))
7.分割整数的最大乘积
import numpy as np
class Solution:
def integerBreak(self, n: int) -> int:
#dp[i]表示整数i对应的最大乘积,dp[i]的值应是dp[j]*(i-j),j属于[1,i-1]的最大值,
#同时注意dp[i]对应的值是经过拆分了的,所以还应判断两个数拆分的情况,即j*(i-j)的值,取最大即可。像2拆成1+1,积是1
dp=np.zeros(n+1,np.int)
dp[0],dp[1]=0,0
for i in range(2,n+1):
for j in range(0,i):
dp[i]=max(dp[i],dp[j]*(i-j),j*(i-j))
return dp[n]
8. 按平方数来分割整数
import numpy as np
import math
class Solution:
def numSquares(self, n: int) -> int:
#dp[i]表示i平方和最小所需要的个数
#dp[i]=min(dp[i],dp[i-j*j]+1)
dp=np.zeros(n+1,np.int)
dp[0],dp[1]=0,1
for i in range(2,n+1):
dp[i]=i
for j in range(1,int(math.sqrt(i))+1):
dp[i]=min(dp[i],dp[i-j*j]+1)
return int(dp[n])
9. 最长递增子序列
import numpy as np
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if not nums:
return 0
dp=np.zeros(len(nums),np.int)
dp[0]=1
for i in range(1,len(nums)):
dp[i]=1
for j in range(0,i):
if(nums[i]>nums[j]):
dp[i]=max(dp[i],dp[j]+1)
return int(max(dp))
10.最长数对链
给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。
现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。
给定一个对数集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
示例 :
输入: [[1,2], [2,3], [3,4]]
输出: 2
解释: 最长的数对链是 [1,2] -> [3,4]
import numpy as np
class Solution:
def findLongestChain(self, pairs: List[List[int]]) -> int:
#dp[i]表示以第i 个元素结尾最多书对链长度
#dp[i]=max(dp[j]+1,dp[i])
#返回列表中最大的
dp=[0]*len(pairs)
dp[0]=1
pairs.sort(key = lambda x:x[1])
for i in range(1,len(pairs)):
dp[i]=1
for j in range(i):
if(pairs[j][1]<pairs[i][0]):
dp[i]=max(dp[j]+1,dp[i])
return max(dp)
11:最长波动序列个数
import numpy as np
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
#首先对list进行去重
#dp[i]代表下标i之前的最大,如果是当前元素是摆动dp[i]=dp[i-1]+1,否则dp[i]=dp[i-1]
result=[]
if not nums:
return 0
result.append(nums[0])
for i in range(1,len(nums)):
if(nums[i]!=nums[i-1]):
result.append(nums[i])
if(len(result)<=2):
return len(result)
dp=np.zeros(len(result),np.int)
dp[0],dp[1]=1,2
for i in range(2,len(result)):
if((result[i]-result[i-1])*(result[i-1]-result[i-2])<0):
dp[i]=dp[i-1]+1
else:
dp[i]=dp[i-1]
return dp[len(result)-1]
12:最长公共子序列
import numpy as np
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m,n=len(text1),len(text2)
dp=np.zeros((m+1,n+1),np.int)
for i in range(1,m+1):
for j in range(1,n+1):
if(text2[j-1]==text1[i-1]):
dp[i][j]=dp[i-1][j-1]+1
else:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
return dp[m][n]
13、最小花费爬楼梯
class Solution:
def minCostClimbingStairs(self , cost: List[int]) -> int:
# write code here
# 动态规划
# 1、确定状态
# 最后一步前必定是在第i-1级台阶 或 第i-2级台阶
# 原问题:求通过第i级台阶所花费的最少代价
# 子问题:求通过第i-1级台阶和通过第i-2级台阶之间花费的最少代价
# 2、转移方程
# f(i) = min {f(i-1)+cost(i-1), f(i-2)+cost(i-2)}
# 3、初始条件
# 因为可以选择直接从台阶0或台阶1开始爬楼梯,所以: f(0)=0, f(1)=0
# 4、计算顺序
# 从小到大依次计算
# 5、编程实现
n = len(cost) # 有n级台阶
f = [0]*(n+1) # 台阶从0开始,所以索引n为楼梯顶部,即有n+1级台阶
for i in range(2, n+1): # 按从小到大的顺序计算
f[i] = min(f[i-1]+cost[i-1], f[i-2]+cost[i-2])
return f[n]
14、 最长公共子串(连续)
class Solution:
def LCS(self , str1: str, str2: str) -> str:
# write code here
maxLen = 0
endIndex = 0
f = [[0 for j in range(len(str2)+1)] for i in range(len(str1)+1)]
for i in range(1, len(str1)+1):
for j in range(1, len(str2)+1):
if (str1[i-1] == str2[j-1]):
f[i][j] = f[i-1][j-1] + 1
else:
f[i][j] = 0
if maxLen < f[i][j]:
maxLen = f[i][j]
endIndex = i # end index of the first string
# print(maxLen)
return str1[endIndex-maxLen:endIndex]
15、 最长公共子串 (不连续)
class Solution:
def LCS(self , s1: str, s2: str) -> str:
if s1 is None or s2 is None:
return '-1'
len1 = len(s1)
len2 = len(s2)
dp = [[''] * (len2 + 1) for i in range(len1 + 1)]
for i in range(1, len1+1):
for j in range(1, len2+1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + s1[i -1]
else:
dp[i][j] = dp[i][j-1] if len(dp[i][j-1]) > len(dp[i-1][j]) else dp[i-1][j]
return dp[-1][-1] if dp[-1][-1] != '' else '-1'
16、把数字翻译成字符串
class Solution:
def solve(self , nums: str) -> int:
# write code here
n = len(nums)
dp = [0] * (n+1)
dp[0] = 1
dp[1] = 1 if nums[0] != '0' else 0
print(dp)
for i in range(2, n+1):
if nums[i-1] != '0':
dp[i] += dp[i-1]
if '10'<= nums[i-2:i] <= '26':
dp[i] += dp[i-2]
return dp[n]
17、 兑换零钱
class Solution:
def minMoney(self , arr: List[int], aim: int) -> int:
# 定义a[i]为组成i的最少货币数
# 状态转移矩阵a[i] = min(a[i-arr[0]], a[i-arr[n]]) + 1
# 输出值a[aim]
# 边界条件: a[i]全部初始化为0即可
a = [0] * (aim + 1)
for i in range(1, aim+1):
min_num = 9999
for coin in arr:
if i >= coin:
min_num = min(min_num, a[i-coin] + 1)
a[i] = min_num
return a[aim] if a[aim] < 9999 else -1
18、连续子数组的最大和
class Solution:
def FindGreatestSumOfSubArray(self , array: List[int]) -> int:
# 定义a[i]为前i个元素的子数组最大和
# 状态转移矩阵为 if a[i-1] <0 then a[i] = arr[i]; if a[i-1]>0 then a[i] = a[i-1] + arr[i]
# 输出max(a[0], a[1], a[m-1])
# a初始化为0即可
m = len(array)
a = [0] * m
a[0] = array[0]
for i in range(1, m):
if a[i-1] < 0:
a[i] = array[i]
else:
a[i] = a[i-1] + array[i]
return max(a)
19、最长回文子串
class Solution:
def getLongestPalindrome(self , A: str) -> int:
# write code here
n = len(A)
dp = [ [0] * n for _ in range(n)]
max_len = 0
for i in range(n - 1, -1, -1):
for j in range(i, n):
if((A[i] == A[j]) and (j - i < 2 or dp[i + 1][j - 1])):
dp[i][j] = 1
max_len = max(max_len, j - i + 1)
return max_len
20、编辑距离
class Solution:
def editDistance(self , str1: str, str2: str) -> int:
# write code here
m, n = len(str1), len(str2)
dp = [[0] * (n+1) for _ in range(m+1)] # 状态转移方程 (m, n) matrix
# 初始化边界
for i in range(m+1):
dp[i][0] = i
for j in range(n+1):
dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
if str1[i-1] == str2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])+1
return dp[m][n]
21、最大正方形
class Solution:
def maximalSquare(self, matrix):
max_side = 0
h,w = len(matrix),len(matrix[0])
dp = [[0 for i in range(w)] for i in range(h)]
print('初始化dp',np.array(dp))
for i in range(h):
dp[i][0] = int(matrix[i][0])
max_side = max(max_side, dp[i][0])
for i in range(w):
dp[0][i] = int(matrix[0][i])
max_side = max(max_side, dp[0][i])
print('初始化边界dp',np.array(dp))
for i in range(1,h):
for j in range(1,w):
if matrix[i][j]=='1':
dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])+1
max_side = max(max_side, dp[i][j])
print('转移好dp',np.array(dp))
return max_side**2
matrix = [["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]]
# matrix = [["0","1"],["1","0"]]
sol = Solution()
res= sol.maximalSquare(matrix)
print(res)
22、目标和
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
sumAll = sum(nums)
if S > sumAll or (S + sumAll) % 2:
return 0
target = (S + sumAll) // 2
dp = [0] * (target + 1)
dp[0] = 1
for num in nums:
for j in range(target, num - 1, -1):
dp[j] = dp[j] + dp[j - num]
return dp[-1]
23、分割等和子集
class Solution:
def canPartition(self, nums: List[int]) -> bool:
total = sum(nums)
if total % 2 == 1: # 总和无法等分
return False
target = total // 2
if max(nums) > target: # 最大值大于总和的一半,无法分割
return False
# 初始化
dp = [False] * (target+1)
dp[0] = True
# 状态更新
for num in nums:
for j in range(target, num-1, -1): # 倒序,且j>=num 【j<num时无需更新dp[j]】
dp[j] |= dp[j-num] # 可选择当前数字num,也可不选
return dp[target]
24、变态跳台阶
public class Solution {
public int JumpFloorII(int target) {
if(target==0||target==1 )
return 1;
else{
int sum=0;
for(int i=1;i<=target;i++)
sum+=JumpFloorII(target-i);//类比上一题,跳两次是f(n-1)+f(n-2)
return sum;
}
}
}
# -*- coding:utf-8 -*-
class Solution:
def jumpFloorII(self, number):
# write code here
num = [0, 1]
while len(num) <= number:
num.append(2*num[-1])
return num[number]
25、矩形覆盖
def answer(num):
dp = np.zeros(num+1)
dp[1], dp[2] = 1, 2
for i in range(num + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[-1]
二:双指针问题
1、两数之和 II - 输入有序数组
题目描述:在有序数组中找出两个数,使它们的和为 target。
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
- 如果 sum > target,移动较大的元素,使 sum 变小一些;
- 如果 sum < target,移动较小的元素,使 sum 变大一些。
数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。
class Solution(object):
def twoSum(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
list=[]
first,latest=0,len(numbers)-1
while(first<latest):
if(numbers[first]+numbers[latest]==target):
list.append(first+1)
list.append(latest+1)
return list
elif(numbers[first]+numbers[latest]>target):
latest=latest-1
else:
first=first+1
2.平方数之和
Input: 5 Output: True Explanation: 1 * 1 + 2 * 2 = 5
题目描述:判断一个非负整数是否为两个整数的平方和。
可以看成是在元素为 0~target 的有序数组中查找两个数,使得这两个数的平方和为 target,如果能找到,则返回 true,表示 target 是两个整数的平方和。
本题和 167. Two Sum II - Input array is sorted 类似,只有一个明显区别:一个是和为 target,一个是平方和为 target。本题同样可以使用双指针得到两个数,使其平方和为 target。
本题的关键是右指针的初始化,实现剪枝,从而降低时间复杂度。设右指针为 x,左指针固定为 0,为了使 02 + x2 的值尽可能接近 target,我们可以将 x 取为 sqrt(target)。
因为最多只需要遍历一次 0~sqrt(target),所以时间复杂度为 O(sqrt(target))。又因为只使用了两个额外的变量,因此空间复杂度为 O(1)。
import math
class Solution:
def judgeSquareSum(self, c: int) -> bool:
first,latest=0,int(math.sqrt(c))
while(first<=latest):
sum=first*first+latest*latest
if(sum==c):
return True
elif(sum>c):
latest=latest-1
else:
first=first+1
return False
3.反转字符串中元音字母
class Solution:
def reverseVowels(self, s: str) -> str:
first,latest=0,len(s)-1
char_list=['a','o','e','i','u','A','E','I','O','U']
temp_list=[]
#str字符串可以看成数组,但是不能修改
for ele in s:
temp_list.append(ele)
while(first<latest):
if(temp_list[first] in char_list and temp_list[latest] in char_list):
temp=temp_list[first]
temp_list[first]=temp_list[latest]
temp_list[latest]=temp
first+=1
latest-=1
elif(temp_list[first] in char_list and temp_list[latest] not in char_list):
latest-=1
else:
first+=1
result=''
for ele in temp_list:
result+=ele
return result
4:回文子串
给定一个非空字符串
s
,最多删除一个字符。判断是否能成为回文字符串。
class Solution:
def validPalindrome(self, s: str) -> bool:
first,late=0,len(s)-1
for i in range(int(len(s)/2)):
if(s[i]==s[late-i]):
continue
else:
return self.judge(s,i+1,late-i) or self.judge(s,i,late-i-1)
return True
def judge(self,s,i,j):
first,late=i,j
count=0
while(first<late):
if(s[first]==s[late]):
first+=1
late-=1
else:
return False
return True
5:链表是否有环
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
p,q=head,head
if(head==None or head.next==None):
return False
while(q.next!=None and p!=None):
p=p.next
q=q.next.next
if(p==q):
return True
return False
6、合并区间
class Solution:
def merge(self , intervals ):
intervals.sort(key=(lambda elme:elme.start))
res = []
for i in range (len(intervals)):
if res == []:
res.append(intervals[i])
else:
if res[-1].end >= intervals[i].start :
res[-1].end = max(intervals[i].end, res[-1].end)
else:
res.append(intervals[i])
return res
7、最长不重复连续子串 (双指针 + set)
class Solution:
def maxLength(self , arr: List[int]) -> int:
# write code here
i, j = 0, 0
val_set = set()
max_len = 0
while i < len(arr) and j < len(arr):
if (arr[j] not in val_set):
val_set.add(arr[j])
max_len = max(max_len, j - i + 1)
j += 1
else:
val_set.remove(arr[i])
i += 1
return max_len
8、接雨水问题
class Solution:
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
left, right = 0, len(height) - 1
left_max, right_max = 0, 0
res = 0
while left < right:
if height[left] < height[right]:
if height[left] >= left_max:
left_max = height[left]
else:
res += left_max - height[left]
left += 1
else:
if height[right] >= right_max:
right_max = height[right]
else:
res += right_max - height[right]
right -= 1
return res
9、盛最多水的容器
class Solution:
def maxArea(self, height: List[int]) -> int:
maxA = 0
i = 0
j = len(height) - 1
while i < j:
h = min(height[i], height[j]);
maxA = max(maxA, h * (j - i));
if height[i] < height[j]:
i = i + 1
else:
j = j - 1
return int(maxA)
10、 最大无序连续子数组
解法一:
使用排序,然后将排序后的数组与排序前对比,找到最开始和最后元素不同的位置
class Solution(object):
def findUnsortedSubarray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
left, right = 0, -1
new_nums = sorted(nums)
for i in range(len(nums)):
if nums[i] != new_nums[i]:
left = i
break
for i in range(len(nums)):
if nums[i] != new_nums[i]:
right = i
return right - left + 1
解法二
从网上学习到一个非常牛的解法,使用双指针;
(1)左指针处理,逆向遍历数组,找到最后大于已遍历部分的极小值位置,即为最初需要变动的元素
(2)右指针处理,正向向遍历数组,找到最后小于已遍历部分的极大值位置,即为最后需要变动的元素位置
class Solution(object):
def findUnsortedSubarray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
left, right = 0, -1
max, min = nums[0], nums[length - 1]
for i in range(length):
if nums[i] < max:
right = i
else:
max = nums[i]
if nums[length - i - 1] > min:
left = length - i - 1
else:
min = nums[length - i - 1]
return right - left + 1
11、交换一次使得数字最大
def change_num():
id1, id2 = -1, -1
max_id = len(nums) - 1
for i in range(len(nums)-1, -1 , -1):
if(nums[i] > nums[max_id]):
max_id = i
elif(nums[i] < nums[max_id]):
id1, id2 = i, max_id
nums[id1],nums[id2] = nums[id2], nums[id1]
if __name__ == '__main__':
nums = [9, 8, 9 , 6, 5]
change_num()
print(nums)
12、丑数
def ugly_num(index):
p2, p3, p5 = 0,0,0
res = [1]
while(len(res) < index):
num = min(res[p2] * 2, res[p3] * 3, res[p5] * 5)
res.append(num)
if(num == res[p2] * 2):
p2 += 1
elif(num == res[p3] * 3):
p3 += 1
else:
p5 += 1
return res[-1]
13、和为s的连续序列
# 双指针,fast 表示 子序列以fast为最右元素
# slow指针判定子序列最左的元素
# 同时从左到右进行遍历
# > tsum 就是减少子序列个数,<tsum 增加子序列个数
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
n = tsum//2+1
fast = 2
slow = 1
res = []
while slow<fast and fast <= n:
curr = (slow+fast)*(fast-slow+1)//2
if curr == tsum:
res.append(list(range(slow,fast+1)))
fast += 1
elif curr < tsum:
fast += 1
else:
slow += 1
return res
三:贪心思想
1、分饼干问题
输入: [1,2,3], [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
m,n=len(g),len(s)
g.sort()
s.sort()
i,j,count=0,0,0
while(i<m and j<n):
if(g[i]<=s[j]):
count+=1
i+=1
j+=1
else:
j+=1
return count
2.无重叠区间(求删除个数)
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
if not intervals:
return 0
intervals.sort(key=lambda x:x[1])
count=1
end=intervals[0][1]
for i in range(1,len(intervals)):
if(intervals[i][0]>=end):
count+=1
end=intervals[i][1]
return len(intervals)-count
3.飞镖气球
class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
#求不重叠区间个数,就是飞镖个数
if not points:
return 0
points.sort(key=lambda x:x[1])
count=1
end=points[0][1]
for i in range(1,len(points)):
if(points[i][0]>end):
end=points[i][1]
count+=1
return count
4.买卖股票(一次交易)
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#一次交易
if not prices:
return 0
max_profit=0
min_price=prices[0]
for i in range(1,len(prices)):
min_price=min(prices[i],min_price)
max_profit=max(max_profit,prices[i]-min_price)
return max_profit
5.买卖股票(多次交易)
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#多次交易
if not prices:
return 0
sum_profit=0
for i in range(1,len(prices)):
if(prices[i]>prices[i-1]):
sum_profit+=prices[i]-prices[i-1]
return sum_profit
6.种花问题
题目描述:flowerbed 数组中 1 表示已经种下了花朵。花朵之间至少需要一个单位的间隔,求解是否能种下 n 朵花。
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
#只需要判断前后即可,防止考虑边界问题,在前后加上[0],只要连续出现在三个[0]就可以种花
flowerbed=[0]+flowerbed+[0]
count=0
for i in range(1,len(flowerbed)-1):
if(flowerbed[i-1]==0 and flowerbed[i]==0 and flowerbed[i+1]==0):
flowerbed[i]=1
count+=1
if(count>=n):
return True
else:
return False
7、s是否是t子串
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
index=-1
for ele in s:
index=t.find(ele,index+1)
if index==-1:
return False
return True
8、分糖果问题
class Solution:
def candy(self , arr ):
# write code here
res = [1] * len(arr)
for i in range(1, len(arr)):
if arr[i] > arr[i-1]:
res[i] = res[i-1] + 1
for i in range(len(arr)-2, -1, -1):
if arr[i] > arr[i+1]:
res[i] = max(res[i+1] + 1, res[i])
return sum(res)
9、主持人调度
class Solution:
def minmumNumberOfHost(self , n: int, startEnd: List[List[int]]) -> int:
start = list()
end =list()
#分别得到活动起始时间
for i in range(n):
start.append(startEnd[i][0])
end.append(startEnd[i][1])
#分别对开始和结束时间排序
start.sort()
end.sort()
res = 0
j = 0
for i in range(n):
#新开始的节目大于上一轮结束的时间,主持人不变
if start[i] >= end[j]:
j += 1
else:
#主持人增加
res += 1
return res
10、跳跃游戏
class Solution:
def canJump(self, nums: List[int]) -> bool:
farest_idx = 0 # 最远可达位置
for i, jump in enumerate(nums):
if i <= farest_idx and farest_idx < i + jump:
farest_idx = i + jump
return farest_idx >= len(nums) - 1
四:栈与队列
1.判断括号
class Solution:
def isValid(self, s: str) -> bool:
stack=[]
if not s:
return True
stack.append(s[0])
for i in range(1,len(s)):
if(len(stack) and ((s[i]==')' and stack[-1]=='(') or (s[i]=='}' and stack[-1]=='{') or (s[i]==']' and stack[-1]=='['))):
stack.pop()
else:
stack.append(s[i])
if(len(stack)>0):
return False
return True
2:数组中元素与下一个比它大的元素之间的距离(气温问题)
Input: [73, 74, 75, 71, 69, 72, 76, 73] Output: [1, 1, 4, 2, 1, 1, 0, 0]
import numpy as np
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
stack=[]
res=np.zeros(len(T),np.int)
stack.append(0)
for cur_index in range(1,len(T)):
while(len(stack)!=0 and T[cur_index]>T[stack[-1]]):#判断条件
pre_index=stack.pop()
res[pre_index]=cur_index-pre_index
stack.append(cur_index)
return res
3.下一个更大元素
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
#遍历列表两次,只将第一次的入队列
list_len=len(nums)
res=[-1]*list_len
stack=[]
for index in range(2*list_len):
while(len(stack) and nums[index%list_len]>nums[stack[-1]]):
pre_index=stack.pop()
res[pre_index]=nums[index%list_len]
if(index<len(nums)):
stack.append(index)
return res
4、用两个栈实现队列
# -*- coding:utf-8 -*-
class Solution:
'''
1.当插入时,直接插入 stack1
2.当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,
如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,
再弹出 stack2 栈顶元素
'''
def __init__(self):
self.stack1= []
self.stack2= []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if len(self.stack2)==0:
while(len(self.stack1)!=0):
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
5、包含min函数的栈
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack = [] #初始化原栈
self.stack_min = [] #初始化最小值栈
def push(self, node):
self.stack.append(node) #往原栈中添加 元素
if not self.stack_min: #一开始也往最小值栈中添加元素
self.stack_min.append(node)
elif node < self.stack_min[-1]: #再次添加元素的时候要同最小值栈中元素比较,小于最小值栈中索引-1的对应值,就把node加入;
self.stack_min.append(node)
else:
self.stack_min.append(self.stack_min[-1]) #否则把索引-1的对应值添加到stack_min中
def pop(self):
self.stack.pop() #弹出栈顶元素则分别获取即可
self.stack_min.pop()
def top(self):
return self.stack[-1] #栈顶元素从原栈中获取
def min(self):
return self.stack_min[-1] #最小值就直接从最小值栈中获取
6、滑动窗口的最大值 (双端队列+单调递减)
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
res=[]
#双端队列
queue=[]#左边做队首,右边做队尾。做成递减队列
for i in range(len(num)):
if len(queue)>0 and i>queue[0]+size-1:#i走到超出原来最大值能覆盖的窗口的位置,那么这个最大值要更新了
queue.pop(0)
while len(queue)>0 and num[i]>num[queue[-1]]:#要进队的数数值大,那就删除所有前面小的数,再把它加进去。
#终止时要加进去的数要么排在第一了,要么就排在比它大的数的后面
#要加len(queue)>0 这个条件,否则当queue被删空了代码就会出现num[-1]这样索引报错的情况
queue.pop()
queue.append(i)
if i>=size-1:
res.append(num[queue[0]])
return res
7、最小的k个数 (堆)
class Solution:
def GetLeastNumbers_Solution(self, a, k):
import heapq
return heapq.nsmallest(k,a)
8、寻找第k大的数 (堆)
import heapq
class Solution:
def findKth(self , a: List[int], n: int, K: int) -> int:
heap = []
for i in range(n):
heapq.heappush(heap, -a[i]) # 小顶堆存进去负数
for i in range(K-1):
heapq.heappop(heap) #出队前K-1个(最大的)
return -heapq.heappop(heap) # 相反数
9、数据流中位数
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.li = []
def Insert(self, num):
for i in range(len(self.li)):
if num < self.li[i]:
self.li.insert(i, num)
break
else:
self.li.append(num)
def GetMedian(self):
length = len(self.li)
if length == 1:
return self.li[0]
return (self.li[length//2] + self.li[(length-1)//2]) / 2
10、字符串解码
class Solution:
def decodeString(self, s):
stack = [] # (str, int) 记录之前的字符串和括号外的上一个数字
num = 0
res = "" # 实时记录当前可以提取出来的字符串
for c in s:
if c.isdigit():
num = num * 10 + int(c)
elif c == "[":
stack.append((res, num))
res, num = "", 0
elif c == "]":
top = stack.pop()
print('===top:', top)
res = top[0] + res * top[1]
print('==res:', res)
else:
res += c
return res
# s = "3[a]2[bc]"
s = "3[a2[c]]"
sol = Solution()
res = sol.decodeString(s)
print('res:', res)
11、LRU缓存机制
class Solution:
def LRU(self , operators: List[List[int]], k: int) -> List[int]:
stack = [] #有序
div_kv = {} #无序
res = [] #结果
for op in operators:
if op[0] == 1:#set操作
if len(stack) >= k:
del div_kv[stack.pop(0)]
if op[1] in div_kv:
stack.remove(op[1])
stack.append(op[1])
div_kv[op[1]] = op[2]
elif op[0] == 2:#get操作
if op[1] not in div_kv:
res.append(-1)
else:
stack.remove(op[1])
stack.append(op[1])
res.append(div_kv[op[1]])
return res
11、栈的压入和弹出
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
if not pushV or len(pushV) != len(popV):
return False
stack = []
for ii in pushV:
stack.append(ii)
while len(stack) and stack[-1] == popV[0]:
stack.pop()
popV.pop(0)
if len(stack):
return False
return True
五:二叉树
1、树高度 num 104
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
else:
LD=self.maxDepth(root.left)
RD=self.maxDepth(root.right)
return max(LD,RD)+1
2、判断是否是avl树 num 110
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def get_depth(root):
if not root:
return 0
else:
LD=get_depth(root.left)
RD=get_depth(root.right)
return max(LD,RD)+1
if not root:
return True
LD=get_depth(root.left)
RD=get_depth(root.right)
if(abs(LD-RD)>1):
return False
return self.isBalanced(root.left) and self.isBalanced(root.right)
3、树直径(高度变种)num 543
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.max=0
#最长路径未必经过根节点
def get_depth(root):
if not root:
return 0
else:
LD=get_depth(root.left)
RD=get_depth(root.right)
self.max=max(LD+RD,self.max)
return max(LD,RD)+1
if not root:
return 0
else:
get_depth(root)
return self.max
4 二叉树镜像
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if root:
self.invertTree(root.left)
self.invertTree(root.right)
temp=root.left
root.left=root.right
root.right=temp
return root
5、两棵树对应节点求和 num 617
class Solution:
def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
#修改之前的树,先序遍历
if not t1:
return t2
if not t2:
return t1
else:
t1.val+=t2.val
t1.left=self.mergeTrees(t1.left,t2.left)
t1.right=self.mergeTrees(t1.right,t2.right)
return t1
6、是否存在叶子节点到根节点总和对应输入的数字 num112
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
#与剑指offer一题目类似
if(not root):
return False
if(not root.left and not root.right and root.val==sum):
return True
sum-=root.val
return self.hasPathSum(root.left,sum) or self.hasPathSum(root.right,sum)
7、判断t是否是s的子树
class Solution:
def isSubtree(self, root: [TreeNode], subRoot: [TreeNode]) -> bool:
def is_equal(root, subRoot):
if not root and not subRoot:
return True
if not subRoot or not root:
return False
if (root.val == subRoot.val):
return is_equal(root.left, subRoot.left) and is_equal(root.right, subRoot.right)
if not root:
return False
return is_equal(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)
8、判断树是否对称 num101
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def dfs(p,q):
#判断子树是否相同
if(not p and not q):
return True
if(not p or not q):
return False
if(p.val==q.val):
return dfs(p.left,q.right) and dfs(p.right,q.left)
if not root:
return True
return dfs(root.left,root.right)
9、树的最小深度
class Solution:
def minDepth(self, root: TreeNode) -> int:
#要注意如果根节点的左或右子树为空的话是构不成子树的。而最小深度是要求从根节点到子树的
if not root:
return 0
elif not root.left:
return self.minDepth(root.right)+1
elif not root.right:
return self.minDepth(root.left)+1
else:
left=self.minDepth(root.left)
right=self.minDepth(root.right)
return min(left,right)+1
10、所有左叶子节点的和
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
#有点疑惑
if not root:
return 0
sum=0
if root.left and not root.left.left and not root.left.right:
sum=sum+root.left.val+self.sumOfLeftLeaves(root.right)
else:
sum=sum+self.sumOfLeftLeaves(root.right)+self.sumOfLeftLeaves(root.left)
return sum
11、相同节点值的最大路径长度(待定)
12、间隔求和
class Solution:
def rob(self, root: TreeNode) -> int:
#后序遍历,树dp,dp[0]代表不抢该节点可以获取的最大值,dp[1]代表抢该节点
def dfs(root):
if not root:
return [0,0]
left=dfs(root.left)
right=dfs(root.right)
result=[0,0]
result[0]=max(left[0],left[1])+max(right[0],right[1])
result[1]=root.val+left[0]+right[0]
return result
res=dfs(root)
return max(res[0],res[1])
13、求第二小的节点
class Solution:
result=[]
def findSecondMinimumValue(self, root: TreeNode) -> int:
def pre_order(root,val_list):
if(root):
pre_order(root.left,val_list)
pre_order(root.right,val_list)
val_list.append(root.val)
val_list=[]
pre_order(root,val_list)
val_list.sort()
val_2 = list(set(val_list))
val_2.sort(key = val_list.index)
if(len(val_2)<2):
return -1
return val_2[1]
14、层次遍历( 一棵树每层节点的平均数)
class Solution:
def averageOfLevels(self, root: TreeNode) -> List[float]:
queue,result=[],[]
queue.append(root)
while(len(queue)):
length,temp_len=len(queue),len(queue)
sum=0
while(length):
length-=1
p=queue.pop(0)
sum+=p.val
if(p.left):
queue.append(p.left)
if(p.right):
queue.append(p.right)
result.append(sum/temp_len)
return result
15、(层序遍历)得到左下角的节点
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
queue=[]
queue.append(root)
while(len(queue)):
#遍历完一层将结果记录下来
length,temp_len=len(queue),len(queue)
level_res=[]
while(length):
length-=1
p=queue.pop(0)
level_res.append(p.val)
if(p.left):
queue.append(p.left)
if(p.right):
queue.append(p.right)
return level_res[0]
16、先序遍历(非递归)
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack=[]
stack.append(root)
result=[]
while(len(stack)>0):
temp=stack.pop()
result.append(temp.val)
if(temp.right):
stack.append(temp.right)
if(temp.left):
stack.append(temp.left)
return result
17、中序遍历(非递归)
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
stack=[]
p=root
result=[]
while(p or len(stack)):
if(p):
stack.append(p)
p=p.left
else:
p=stack.pop()
result.append(p.val)
p=p.right
return result
18、修剪二叉树(节点值全部在(L,R)之间)
class Solution:
def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
if not root:
return None
elif(root.val>R):
return self.trimBST(root.left,L,R)
elif(root.val<L):
return self.trimBST(root.right,L,R)
else:
root.left=self.trimBST(root.left,L,R)
root.right=self.trimBST(root.right,L,R)
return root
19、第k小的元素
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.count=0
self.res=0
def in_order(root):
if not root:
return
else:
in_order(root.left)
self.count+=1
if(self.count==k):
self.res=root.val
in_order(root.right)
in_order(root)
return self.res
20、二叉搜索树转换为累加树
class Solution:
def convertBST(self, root: TreeNode) -> TreeNode:
self.sum=0
def in_order(root):
if root:
in_order(root.right)
self.sum+=root.val
root.val=self.sum
in_order(root.left)
return root
return in_order(root)
21、最底的公共祖先
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root:
return None
if(p==root):
return p
if(q==root):
return q
L=self.lowestCommonAncestor(root.left,p,q)
R=self.lowestCommonAncestor(root.right,p,q)
if( L and R):
return root
elif not R:
return L
else:
return R
22、从有序数组中构造二叉查找树
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
def mid_build(ele_list,l,r):
if(l>r):
return None
mid=(l+r)>>1
root=TreeNode(nums[mid])
root.left=mid_build(ele_list,l,mid-1)
root.right=mid_build(ele_list,mid+1,r)
return root
if not nums:
return
return mid_build(nums,0,len(nums)-1)
23、 在二叉查找树中寻找两个节点,使它们的和为一个给定值
class Solution:
def findTarget(self, root: TreeNode, k: int) -> bool:
res_set=set()
visit=[]
def in_order(root,target):
if root:
if(root.val not in res_set):
res_set.add(root.val)
if(k-root.val in res_set and k!=2*root.val):
return True
L=in_order(root.left,target)
R=in_order(root.right,target)
return L or R
return in_order(root,k)
24、二叉搜索树的最小绝对差
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
min_value=1000
res=[]
stack=[]
p=root
while(p or len(stack)):
if(p):
stack.append(p)
p=p.left
else:
p=stack.pop()
if(len(res)):
min_value=min(min_value,abs(p.val-res[-1]))
res.append(p.val)
p=p.right
return min_value
25、二叉搜索树(众树)
class Solution:
def findMode(self, root: TreeNode) -> List[int]:
res_dict={}
res=[]
def in_order(root):
if root:
in_order(root.left)
if(root.val not in res_dict):
res_dict[root.val]=1
else:
res_dict[root.val]+=1
in_order(root.right)
in_order(root)
if not root:
return
res_list=sorted(res_dict.items(),key=lambda x:x[1],reverse=True)
num=res_list[0][1]
res.append(res_list[0][0])
for ele in res_list[1:]:
if(ele[1] == num):
res.append(ele[0])
return res
26、前缀树(待定更新)
27、二叉树后续遍历(非递归)
class Solution:
def postorderTraversal(self, root): #迭代法1
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
# 中结点先处理
result.append(node.val)
# 左孩子先入栈
if node.left:
stack.append(node.left)
# 右孩子后入栈
if node.right:
stack.append(node.right)
# 将最终的数组翻转
return result[::-1]
28 按之字形顺序打印二叉树
# 层序遍历的时候加个反向的flag。
class Solution:
def Print(self , pRoot: TreeNode) -> List[List[int]]:
# write code here
if not pRoot: return []
quene = []
res = []
quene.append(pRoot)
reverseFlag = True
while quene:
row = []
for i in range(len(quene)):
node = quene.pop(0)
row.append(node.val)
if node.left:
quene.append(node.left)
if node.right:
quene.append(node.right)
reverseFlag = not reverseFlag
if reverseFlag:
res.append(row[::-1])
else:
res.append(row)
return res
29、 判断是不是二叉搜索树 (中序遍历的结果是不是顺序)
class Solution:
def inOrderTraversal(self, root: TreeNode) -> List[int]:
if root is None:
return []
return self.inOrderTraversal(root.left) + [root.val] + self.inOrderTraversal(root.right)
def isValidBST(self , root: TreeNode) -> bool:
res = self.inOrderTraversal(root)
if len(res) <= 1:
return True
for i in range(len(res)-1):
if res[i] >= res[i+1]:
return False
return True
30、判断是不是完全二叉树
class Solution:
def isCompleteTree(self , root: TreeNode) -> bool:
if root is None:
return True
ret = [root]
while ret:
cur = ret.pop(0)
if cur:
ret.append(cur.left)
ret.append(cur.right)
else:
break
for i in ret:
if i:
return False
return True
31、序列化和反序列化(前序)
class Solution:
str1 = []
def Serialize(self, root):
# write code here
if root == None:
self.str1.append("#")
return self.str1
self.str1.append(str(root.val))
self.Serialize(root.left)
self.Serialize(root.right)
return self.str1
start=-1
def Deserialize(self, s):
# write code here
self.start=self.start+1;
if self.start>=len(s) or s[self.start]=="#" or s==None :return ;
cur=TreeNode(int(s[self.start]))
cur.left=self.Deserialize(s)
cur.right=self.Deserialize(s)
return cur
32、重建二叉树
class Solution:
def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
# write code here
if not pre or not vin:
return None
#构造根节点,寻找左右子树的分界线
root = TreeNode(pre[0])
n = vin.index(pre[0])
#构造左右子树,递归调用
root.left = self.reConstructBinaryTree(pre[1:n + 1], vin[:n])
root.right = self.reConstructBinaryTree(pre[n + 1:], vin[n + 1:])
#返回根节点
return root
32、前缀树
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = {}
self.word_end = -1
def insert(self, word):
"""
Inserts a word into the trie.
"""
curNode = self.root
for c in word:
if c not in curNode:
curNode[c] = {}
curNode = curNode[c]
curNode[self.word_end] = True
# print('==curNode:', curNode)
def search(self, word):
"""
Retu
rns if the word is in the trie.
"""
curNode = self.root
for c in word:
if c not in curNode:
return False
curNode = curNode[c]
if self.word_end not in curNode:
return False
return True
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
curNode = self.root
for c in prefix:
if c not in curNode:
return False
curNode = curNode[c]
return True
word = 'apple'
prefix = 'ad'
obj = Trie()
obj.insert(word='apple')
obj.insert(word='add')
# obj.insert(word='app')
print('tree:', obj.root)
param_2 = obj.search(word)
print('search res:', param_2)
param_3 = obj.startsWith(prefix)
print('==param_3:', param_3)
六:二分法
1.求开方
lass Solution:
def mySqrt(self, x: int) -> int:
low,high=0,x
if x==0 or x==1:
return x
while(low<high):
mid=(low+high)>>1
val=mid*mid
val_1=(mid+1)*(mid+1)
if(val<=x<val_1):
return mid
elif(val>=x):
high=mid
else:
low=mid
2、大于给定元素的最小元素
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
#不需要等于,返回low
low,high=0,len(letters)-1
while(low<high):
mid=(low+high)>>1
if(target<letters[mid]):
high=mid-1
else:
low=mid+1
if(letters[low]<=target):
return letters[(low+1)%len(letters)]
return letters[low]
3、有序数组只有一个数不出现两次,找出这个数。
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
low,high=0,len(nums)-1
while(low<high):
mid=(low+high)>>1
if(mid%2):
mid-=1
if(nums[mid+1]==nums[mid]):
low=mid+2
else:
high=mid
return nums[low]
4、第一个错误版本
class Solution:
def firstBadVersion(self, n):
"""
:type n: int
:rtype: int
"""
low,high=1,n
while(low<high):
mid=(low+high)>>1
if(not isBadVersion(mid)):
low=mid+1
else:
high=mid-1
if isBadVersion(low):
return low
return low+1
5、旋转数组最小数字
class Solution:
def findMin(self, nums: List[int]) -> int:
low,high=0,len(nums)-1
if(len(nums)==1):
return nums[0]
while(nums[low]>nums[high]):
mid=(low+high)>>1
if(high<low):
break
elif(nums[mid]>nums[low]):
low=mid
else:
high=mid
if(nums[low]<nums[low-1]):
return nums[low]
return nums[low+1]
6、查找连续数组
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if(target not in nums):
return [-1,-1]
nums=list(map(float,nums))
def bin_search(nums, target):
low, high = 0, len(nums) - 1
while (low < high):
mid = int((low + high) / 2)
if (target == nums[mid]):
return mid
elif (target > nums[mid]):
low = mid + 1
else:
high = mid - 1
return low
a,b=target-0.5,target+0.5
i,j=bin_search(nums,a),bin_search(nums,b)
if(nums[i]!=target):
i=i+1
if(nums[j]!=target):
j=j-1
return [i,j]
7、有序数组二分查找
class Solution:
def search(self , nums, target):
# write code here
length = len(nums)
left = 0
right = length
if length < 1:
return -1
while left <= right:
mid = int((left + right) / 2)
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
8、寻找峰值
class Solution:
def findPeakElement(self , nums: List[int]) -> int:
left,right = 0,len(nums)-1
while left<right:
mid = (left+right)//2
if nums[mid] < nums[mid+1]: left = mid+1
else: right = mid
return left
9、版本号比较
def compare(s1, s2):
s1_val_list, s2_val_list = s1.split('.'), s2.split('.')
len_s1, len_s2 = len(s1_val_list), len(s2_val_list)
max_len = max(len_s1, len_s2)
if (len_s1 < max_len):
s1_val_list += [0] * (max_len - len_s1)
if (len_s2 < max_len):
s2_val_list += [0] * (max_len - len_s2)
for i in range(max_len):
n1 = int(s1_val_list[i])
n2 = int(s2_val_list[i])
if(n1 > n2):
return 1
if(n1 < n2):
return 0
versions = ['4.8', '1.7.1', '4.1.9', '5.0.0.0']
for i in range(len(versions)-1, -1, -1):
for j in range(i):
if(compare(versions[j], versions[j+1])):
versions[j], versions[j+1] = versions[j+1], versions[j]
七:搜索问题
1、最短路径(BFS)
class Solution:
def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
#bfs
queue=[]
rows,cols=len(grid),len(grid[0])
if(rows==1 and cols==1 and grid[0][0]==0):
return 1
if(grid[0][0]==1 or grid[rows-1][cols-1]==1):
return -1
queue.append([0,0])
level=1
grid[0][0]=1
next_step=[[0,1],[1,0],[0,-1],[-1,0],[-1,-1],[1,1],[1,-1],[-1,1]]
while(queue):
length=len(queue)
while(length):
cur=queue.pop(0)
x=cur[0]
y=cur[1]
length-=1
if(x==rows-1 and y==cols-1):
return level
for i in range(len(next_step)):
x+=next_step[i][0]
y+=next_step[i][1]
if(x>=0 and x<rows and y>=0 and y<cols and grid[x][y]==0):
queue.append([x,y])
grid[x][y]=1
else:
continue
level+=1
return -1
2、岛屿最大面积,连续一的个数(DFS)
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
def dfs(grid,i,j):
if(i<0 or i>=len(grid) or j<0 or j>=len(grid[0]) or grid[i][j]==0):
return 0
grid[i][j]=0
count=1
count += dfs(grid, i+1, j);
count += dfs(grid, i-1, j);
count += dfs(grid, i, j+1);
count += dfs(grid, i, j-1);
return count
max_count=0
for i in range(len(grid)):
for j in range(len(grid[0])):
if(grid[i][j]==0):
continue
else:
max_count=max(max_count,dfs(grid,i,j))
return max_count
3、岛屿数量(DFS)
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
def dfs(grid,i,j):
if(i<0 or i>=len(grid) or j<0 or j>=len(grid[0]) or grid[i][j]=='0' ):
return
grid[i][j]='0'
dfs(grid,i+1,j)
dfs(grid,i,j+1)
dfs(grid,i-1,j)
dfs(grid,i,j-1)
count=0
for i in range(len(grid)):
for j in range(len(grid[0])):
if(grid[i][j]=='1'):
count+=1
dfs(grid,i,j)
return count
4、好友关系个数(DFS)
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
#最基本的dfs
visited=[0]*len(M)
def dfs(i):
for j in range(len(M)):
if(visited[j]==0 and M[i][j]==1):
visited[j]=1
dfs(j)
count=0
for i in range(len(M)):
if(visited[i]==0):
count+=1
dfs(i)
return count
5、填充边界的O
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
#对边界的那些‘O’进行dfs改变值,t
def dfs(grad,i,j):
if(i<0 or i>=len(board) or j<0 or j>=len(board[0]) or board[i][j]!='O'):
return
board[i][j]='-'
dfs(board,i-1,j)
dfs(board,i+1,j)
dfs(board,i,j-1)
dfs(board,i,j+1)
for i in range(len(board)):
for j in range(len(board[0])):
if((i==0 or i==len(board)-1 or j==0 or j==len(board[0])-1) and board[i][j]=='O'):
dfs(board,i,j)
for i in range(len(board)):
for j in range(len(board[0])):
if(board[i][j]=='O'):
board[i][j]='X'
if(board[i][j]=='-'):
board[i][j]='O'
6、手机键盘组合(回溯)
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
res=[]
hash_table={'2':'abc','3':'def','4':'ghi','5':'jkl','6':'mno','7':'pqrs','8':'tuv','9':'wxyz'}
def dfs(index,cur_str):
if(index==len(digits)):
res.append(cur_str)
return
val=hash_table[digits[index]]
for i in range(len(val)):
cur_str=cur_str+val[i]
dfs(index+1,cur_str)
cur_str=cur_str[0:-1]
dfs(0,'')
return res
7、IP地址划分
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
res = []
for i in range(1, 4):
for j in range(i+1, i + 4):
for k in range(j+1, j + 4):
num_1, num_2, num_3, num_4 = s[0:i], s[i:j], s[j:k], s[k:len(s)]
if(len(s)-k>=4):
continue
try:
if((num_1.startswith('0') and len(num_1)!=1) or (num_2.startswith('0') and len(num_2)!=1) or (num_3.startswith('0') and len(num_3)!=1) or (num_4.startswith('0') and len(num_4)!=1)):
continue
if (0 <= int(num_1) <= 255 and 0 <=int(num_2) <= 255 and 0 <= int(num_3) <= 255 and 0 <= int(num_4) <= 255):
res.append(num_1 + '.' + num_2 + '.' + num_3 + '.' + num_4)
except:
continue
return res
8、单词搜索(回溯)
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
self.rows,self.cols=len(board),len(board[0])
def search(i,j,index):
if(index>=len(word)):
return True
if(i>=self.rows or j>=self.cols or i<0 or j<0 or board[i][j]!=word[index]):
return False
board[i][j]+='1'#改变之前的,是为了防止同一个单元格的元素多次使用,比如说eae,ea就可以走出eae
res=(search(i,j+1,index+1) or search(i+1,j,index+1) or search(i,j-1,index+1)or search(i-1,j,index+1))
board[i][j]=board[i][j][:-1]#改为原来的值
return res
for i in range(len(board)):
for j in range(len(board[0])):
if(board[i][j]==word[0]):
if(search(i,j,0)):
return True
return False
9、给定一个 没有重复 数字的序列,返回其所有可能的全排列。(回溯)
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
#啊哈算法全排列,浅拷贝和深拷贝
temp_list=[0]*len(nums)
book=[0]*len(nums)
res_list=[]
def dfs(step):
if(step==len(nums)):
res_list.append(temp_list.copy())
return
for i in range(len(nums)):
if(book[i]==0):
temp_list[step]=nums[i]
book[i]=1
dfs(step+1)
book[i]=0
dfs(0)
return res_list
10、有相同元素全排列
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
#啊哈算法全排列,浅拷贝和深拷贝
temp_list=[0]*len(nums)
book=[0]*len(nums)
res_list=[]
def dfs(step):
if(step==len(nums)):
res_list.append(temp_list.copy())
return
for i in range(len(nums)):
if(book[i]==0):
temp_list[step]=nums[i]
book[i]=1
dfs(step+1)
book[i]=0
dfs(0)
set_list=[]
for ele in res_list:
if ele not in set_list:
set_list.append(ele)
return set_list
11、组合
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
temp_val = []
res_list = []
def dfs(step):
if (len(temp_val) == k):
res_list.append(temp_val.copy())
return
else:
for index in range(step+1, n+1):
temp_val.append(index)
dfs(index)
temp_val.pop()
dfs(0)
return res_list
12、括号生成
class Solution:
def recursion(self, string, res, length):
tmp = "".join(string)
if len(string) == length:
res.add(tmp)
return res
for i in range(len(string)):
string.insert(i, ')')
string.insert(i, '(')
self.recursion(string, res, length)
string.pop(i)
string.pop(i)
def generateParenthesis(self , n):
# write code here
length = 2*n
string = ['(',')']
res = set()
self.recursion(string, res, length)
res = list(res)
return res
13、矩阵递增序列
class Solution:
global dirs
#记录四个方向
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
global n, m
#深度优先搜索,返回最大单元格数
def dfs(self, matrix:List[List[int]], dp: List[List[int]], i:int, j:int) :
if dp[i][j] != 0:
return dp[i][j]
dp[i][j] += 1
for k in range(4):
nexti = i + dirs[k][0]
nextj = j + dirs[k][1]
#判断条件
if nexti >= 0 and nexti < n and nextj >= 0 and nextj < m and matrix[nexti][nextj] > matrix[i][j]:
dp[i][j] = max(dp[i][j], self.dfs(matrix, dp, nexti, nextj) + 1)
return dp[i][j]
def solve(self , matrix: List[List[int]]) -> int:
global n,m
#矩阵不为空
if len(matrix) == 0 or len(matrix[0]) == 0:
return 0
res = 0
n = len(matrix)
m = len(matrix[0])
#i,j处的单元格拥有的最长递增路径
dp = [[0 for col in range(m)] for row in range(n)]
for i in range(n):
for j in range(m):
#更新最大值
res = max(res, self.dfs(matrix, dp, i, j))
return res
14、课程表 (拓扑排序)
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 入度列表
print('==indegrees:', indegrees)
adjacency = [[] for i in range(numCourses)] # 邻接列表 存储节点的下一个节点
print('=adjacency:', adjacency)
#得到入度和每个课程的邻接列表
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre].append(cur)
print('====indegrees:', indegrees)
print('====adjacency:', adjacency)
quene = []
# 如果度为0 就进入队列
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
while quene:
node = quene.pop(0)
num_nodes += 1
for next_node in adjacency[node]:
indegrees[next_node] -= 1 # 找出下一个点相应的度-1
if indegrees[next_node] == 0: # 入度为0
quene.append(next_node)
print('==num_nodes:', num_nodes)
return num_nodes == numCourses
numCourses, prerequisites = 6, [[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
sol = Solution()
res = sol.canFinish(numCourses, prerequisites)
print('res:', res)
17、课程表 (记录路径)
class Solution:
def canFinish(self, numCourses, prerequisites):
indegrees = [0] * numCourses # 入度列表
print('==indegrees:', indegrees)
adjacency = [[] for i in range(numCourses)] # 邻接列表
print('=adjacency:', adjacency)
#得到入度和每个课程的邻接列表
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre].append(cur)
print('====indegrees:', indegrees)
print('====adjacency:', adjacency)
quene = []
# 如果度为0 就进入队列
for i in range(len(indegrees)):
if indegrees[i] == 0:
quene.append(i)
print('==quene:', quene)
num_nodes = 0
learn_node = []
while quene:
node = quene.pop(0)
print('=======node', node)
learn_node.append(node)
num_nodes += 1
for next_node in adjacency[node]:
indegrees[next_node] -= 1 # 找出下一个点相应的度-1
if indegrees[next_node] == 0: # 入度为0
quene.append(next_node)
print('==num_nodes:', num_nodes)
return learn_node if num_nodes == numCourses else []
# numCourses, prerequisites = 2, [[1, 0]]
# numCourses, prerequisites = 2, [[1, 0], [0, 1]]
numCourses, prerequisites = 6, [[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
sol = Solution()
res = sol.canFinish(numCourses, prerequisites)
print('res:', res)
18、求1+2+3+...+n
class Solution {
public:
int Sum_Solution(int n) {
n && (n += Sum_Solution(n - 1));
return n;
}
};
八:HASH表专题:
1、数组中两个数的和为给定值(双指针和hash表解决)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
res=[]
return_list=[]
for i in range(len(nums)):
if((target-nums[i]) in nums and nums.index(target-nums[i])!=i):
return [i,nums.index(target-nums[i])]
return []
2、存在重复元素
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
res_set=set()
for i in range(len(nums)):
if(nums[i] not in res_set):
res_set.add(nums[i])
else:
return True
return False
3、最长和谐子序列
class Solution:
def findLHS(self, nums: List[int]) -> int:
if not nums:
return 0
res_dict={}
max_res=0
for i in range(len(nums)):
if(nums[i] not in res_dict):
res_dict[nums[i]]=1
else:
res_dict[nums[i]]+=1
for i in range(1,len(nums)):
if( (nums[i]-1) in res_dict):
max_res=max(max_res,res_dict[nums[i]]+res_dict[nums[i]-1])
return max_res
4、最长连续序列(桶排序和set)
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
#用set存储然后遍历查找,只往后查找
ele_set = set()
max_len = 0
for ele in nums:
if (ele not in ele_set):
ele_set.add(ele)
for ele in nums:
if ((ele - 1) not in ele_set):
cur_num = ele
temp_len = 0
while (cur_num in ele_set):
temp_len += 1
cur_num += 1
max_len = max(max_len, temp_len)
return max_len
5、三数之和
class Solution:
def threeSum(self , num: List[int]) -> List[List[int]]:
# write code here
if len(num) < 3:
return []
help = {}
res = []
num = sorted(num)
for i in range(len(num)-2):
target = -num[i]
l = i + 1
r = len(num) - 1
while l < r:
if num[l] + num[r] == target:
res.append((num[i], num[l], num[r]))
res = list(set(res))
l += 1
elif num[l] + num[r] < target:
l += 1
else:
r -= 1
return res
6、和为k的连续子数组 (前缀和 + hashmap)
思路 – hashtable
通过前缀和求解,令P[i] = A[0] + A[1] + … + A[i-1], 令P[j] = A[0] + … + A[j-1],
满足题目条件为 S = P[j] - P[i],目标是计算有多少个S。
- 方法为使用一个hashtable,key为前缀和,value为这个前缀和出现的次数。
- 当我们计算到i时,ret += hashtable.get(P[i+1] - S, 0)
- 同时更新 hashtable[P[i+1]] += 1
class Solution: def subarraySum(self, nums: List[int], k: int) -> int: pre_sum = {0:1} cur_sum = 0 res = 0 for i in nums: cur_sum += i if cur_sum - k in pre_sum: res += pre_sum[cur_sum - k] pre_sum[cur_sum] = pre_sum[cur_sum] + 1 if cur_sum in pre_sum else 1 return res
九:字符串专题:
1、两个字符串包含的字符是否完全相同(排序后判断即可)
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
s="".join((lambda x:(x.sort(),x)[1])(list(s)))
t="".join((lambda x:(x.sort(),x)[1])(list(t)))
if(len(s)!=len(t)):
return False
for i in range(len(s)):
if(s[i]!=t[i]):
return False
return True
2、计算一组字符集合可以组成的回文字符串的最大长度(统计每个字符出现次数)
class Solution:
def longestPalindrome(self, s: str) -> int:
count = collections.Counter(s)
length=0
for ele in count.values():
length+=int(ele/2)*2
if(length%2==0 and ele%2==1):
length+=1
return length
3、同构字符串
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
for i in range(len(s)):
if(s.find(s[i])==t.find(t[i])):
continue
else:
return False
return True
4、判断一个整数是否是回文数(转成字符双指针或者求回文的数)
class Solution:
def isPalindrome(self, x: int) -> bool:
if(x<0):
return False
if -1<x<10:
return True
s=str(x)
begin,end=0,len(s)-1
while(begin<end):
if(s[begin]!=s[end]):
return False
else:
begin+=1
end-=1
return True
5、统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
class Solution:
def countBinarySubstrings(self, s: str) -> int:
#从前往后统计每个连续区间相同数字个数
if(len(s)<2):
return 0
count=1
count_list=[]
for i in range(1,len(s)):
if(s[i]==s[i-1]):
count+=1
else:
count_list.append(count)
count=1
count_list.append(count)
if(len(count_list)<2):
return 0
sum=0
for j in range(1,len(count_list)):
sum+=min(count_list[j],count_list[j-1])
return sum
6、字符串变形
class Solution:
def trans(self , s: str, n: int) -> str:
# write code here
s0=[]
for i in s:
if i!=' ':
if i.islower():
s0.append(i.upper())
else:
s0.append(i.lower())
else:
s0.append(' ')
s0=''.join(s0).split(' ')
return ' '.join(s0[::-1])
7、最长公共前缀字符串
class Solution:
def longestCommonPrefix(self , strs: List[str]) -> str:
# write code here
if len(strs) == 0:
return ''
pre_str = strs[0]
for string in strs[1:]:
if pre_str in string:
continue
elif string in pre_str:
pre_str = string
else:
while pre_str not in string:
pre_str = pre_str[:-1]
return pre_str
8、大数加法
class Solution:
def solve(self , s: str, t: str) -> str:
# write code here
if not s: return t
if not t: return s
res = ''
carry = 0
i = len(s) - 1
j = len(t) - 1
while i >= 0 or j >= 0:
n1 = s[i] if i >= 0 else 0
n2 = t[j] if j >= 0 else 0
tmp = int(n1) + int(n2) + carry
carry = tmp // 10
res = str(tmp % 10) + res
i -= 1
j -= 1
if carry:
return '1'+res
else:
return res
9、验证IP地址
class Solution:
def ipv4(self, ip: str) -> str:
flag = True
for x in ip.split("."):
if len(x) > 3:
flag = False
break
for xi in x:
if not "0" <= xi <= "9":
flag = False
break
if not flag:
break
if x[0] == "0" or int(x) < 0 or int(x) > 255:
flag = False
break
return "IPv4" if flag else "Neither"
def ipv6(self, ip: str) -> str:
def check(digit):
try:
res = int(digit, 16)
return True
except Exception:
return False
flag = True
for x in ip.split(":"):
if not x or len(x) > 4 or not check(x.upper()) or int(x.upper(), 16) < 0 or int(x.upper(), 16) > 65536:
flag = False
break
return "IPv6" if flag else "Neither"
def solve(self , IP: str) -> str:
# write code here
if ":" in IP:
# ip6
if len(IP.split(":")) != 8: return "Neither"
return self.ipv6(IP)
elif "." in IP:
if len(IP.split(".")) != 4: return "Neither"
return self.ipv4(IP)
else:
return "Neither"
10、
十:数组和矩阵专题
1、移动0
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
count=0
for ele in nums:
if(ele!=0):
count+=1
k=0
for i in range(len(nums)):
if(nums[i]!=0):
nums[k]=nums[i]
k+=1
for i in range(count,len(nums)):
nums[i]=0
2、改变矩阵维度
class Solution:
def matrixReshape(self, nums: List[List[int]], r: int, c: int) -> List[List[int]]:
if(len(nums)*len(nums[0])<r*c):
return nums
new_martix=[]
row_index,col_index=0,0
one_row=[]
for i in range(len(nums)):
for j in range(len(nums[0])):
if(col_index<c):
one_row.append(nums[i][j])
col_index+=1
else:
col_index=0
new_martix.append(one_row.copy())
one_row=[nums[i][j]]
col_index+=1
new_martix.append(one_row)
return new_martix
3、最长连续的1
class Solution:
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
if not nums:
return 0
count=0
if(nums[0]==0):
count=0
else:
count=1
max_count=count
for i in range(1,len(nums)):
if(nums[i]==nums[i-1] and nums[i]==1):
count+=1
max_count=max(max_count,count)
elif(nums[i]==1):
count=1
max_count=max(max_count,count)
return max_count
4、有序矩阵查找
class Solution:
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
row_index,col_index=0,len(matrix[0])-1
while(row_index<len(matrix) and col_index >=0 ):
if(matrix[row_index][col_index]==target):
return True
elif(target<matrix[row_index][col_index]):
col_index-=1
else:
row_index+=1
return False
5、一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数
集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复,找出重复的数和缺失的数。
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
#其实就是找第一个
for index in range(len(nums)):
while(nums[index]!= index+1):
#这里终止一定要注意
if(nums[index]==nums[nums[index]-1]):
break
temp=nums[nums[index]-1]
nums[nums[index]-1]=nums[index]
nums[index]=temp
for index in range(len(nums)):
if(nums[index]!= index+1):
return [nums[index],index+1]
6、(二分)找出数组中重复的数,数组值在 [1, n] 之间(要求不能修改数组,也不能使用额外的空间。)
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
low,high=1,len(nums)-1
mid=-1
while(low<high):
mid=(low+high)>>1
count=0
for ele in nums:
if(ele <= mid):
count+=1
if(count<=mid):
low=mid+1
else:
high=mid
return low
7、数组的度
class Solution:
def findShortestSubArray(self, nums: List[int]) -> int:
freq,left,right={},{},{}
for index,ele in enumerate(nums):
if(ele not in freq):
freq[ele]=1
left[ele]=index
else:
freq[ele]+=1
right[ele]=index
degree=max(freq.values())
return min(right[i]-left[i]+1 for i,v in freq.items() if v==degree)
8、对角元素相等的矩阵
class Solution:
def isToeplitzMatrix(self, matrix: List[List[int]]) -> bool:
#只需要判断当前行除了最后一个元素和后一行除了第一个元素是否相等
rows,cols=len(matrix),len(matrix[0])
if(rows==1 or cols==1):
return True
for index in range(rows-1):
if(matrix[index][:-1]!=matrix[index+1][1:]):
return False
return True
9、S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i],指导首尾相等
class Solution:
def arrayNesting(self, nums: List[int]) -> int:
#寻找最大长度的环
max_len=1
for index in range(len(nums)):
if(max_len>len(nums)/2):
return max_len
start_num=nums[index]
temp_num=nums[start_num]
temp_len=1
while(temp_num!=start_num):
temp_len+=1
temp_num=nums[temp_num]
max_len=max(max_len,temp_len)
return max_len
10、分隔数组,使得对每部分排序后数组就为有序。
class Solution:
def maxChunksToSorted(self, arr: List[int]) -> int:
#当遍历到第i个位置时,如果可以切分为块,那前i个位置的最大值一定等于i。
#否则,一定有比i小的数划分到后面的块,那块排序后,一定不满足升序。
max_value,count=-100,0
for i in range(len(arr)):
max_value=max(max_value,arr[i])
if(max_value==i):
count+=1
return count
11、螺旋矩阵
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param matrix int整型二维数组
# @return int整型一维数组
#
class Solution:
def spiralOrder(self , matrix: List[List[int]]) -> List[int]:
# write code here
if matrix == []:
return []
m,n = len(matrix),len(matrix[0])
up,down = 0,m-1
left,right = 0,n-1
res = []
while left<=right and up<=down:
for i in range(left,right+1):
res.append(matrix[up][i])
up += 1
if up > down:
break
for i in range(up,down+1):
res.append(matrix[i][right])
right -= 1
if right < left:
break
for i in range(right,left-1,-1):
res.append(matrix[down][i])
down -= 1
if up > down:
break
for i in range(down,up-1,-1):
res.append(matrix[i][left])
left += 1
if left > right:
break
return res
12、 顺时针旋转矩阵
class Solution:
def rotateMatrix(self , mat: List[List[int]], n: int) -> List[List[int]]:
for i in range(n):
for j in range(i):
temp = mat[i][j]
mat[i][j] = mat[j][i]
mat[j][i] = temp
for i in range(n):
mat[i].reverse()
return mat
13、旋转数组
class Solution:
def solve(self , n: int, m: int, a: List[int]) -> List[int]:
m = m % n
return a[n-m:] + a[:n-m]
14、调整数组顺序使奇数位于偶数前面
# -*- coding:utf-8 -*-
# 不新建数组,类似于冒泡排序
class Solution:
def reOrderArray(self, array):
# write code here
for i in range(0,len(array)):
for j in range(len(array)-1,i,-1):
if array[j-1]%2 ==0 and array[j]%2==1:
temp = array[j-1]
array[j-1] = array[j]
array[j] = temp
return array
注意:对于本题的变体,本人在面试中被问到过,被问的是“不开辟新空间的条件下,使奇数在前,偶数在后”,面试官给的答案是设置两个偶、奇指针,分别位于数组的开头和末尾,当遇到偶数、奇数时交换。
15、数组中出现次数超过一半的数字
# -*- coding:utf-8 -*-
import collections
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
temp = collections.Counter(numbers)
num = len(numbers)/2
for k,v in temp.items():
if v > num:
return k
return 0
16、把数组排成最小的数
# -*- coding:utf-8 -*-
class Solution:
def PrintMinNumber(self, numbers):
# write code here
if not numbers:
return ""
num=map(str,numbers)
num.sort(lambda x,y:cmp(x+y,y+x))
return ''.join(num)
17、构建乘积数组
class Solution:
def multiply(self , A: List[int]) -> List[int]:
# 初始化数组B
B = [1 for i in range(len(A))]
# 先乘左边,从左到右
for i in range(1, len(A)):
B[i] = B[i -1] * A[i -1]
temp = 1
# 再乘右边,从右到左
for i in reversed(range(len(A))):
B[i] *= temp
temp *= A[i]
return B
17、扑克牌顺子
public class Solution {
public boolean isContinuous(int [] numbers) {
int[]d = new int[14];
d[0] = -5;
int len = numbers.length;
if(len==0)
return false;
int max = -1;
int min = 14;
for(int i =0;i<len;i++){
d[numbers[i]]++;
if(numbers[i] == 0){
continue;
}
if(d[numbers[i]]>1){
return false;
}
if(numbers[i] >max){
max = numbers[i];
}
if(numbers[i] <min){
min = numbers[i];
}
}
if(max-min<5){
return true;
}
return false;
}
}
18、孩子们的游戏-圆圈中最后剩下的数
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if (m == 0 || n == 0) {
return -1;
}
ArrayList<Integer> data = new ArrayList<Integer>();
for (int i = 0; i < n; i++) {
data.add(i);
}
int index=0;
while(data.size()>1){
index=(index+m-1)%data.size();
data.remove(index);
}
return data.get(0);
}
}
19、不用加减乘除做加法
public class Solution {
public int Add(int num1,int num2) {
if(num1>0){
while(num1--!=0)
num2++;
}
else if(num1<0){
while(num1++!=0)
num2--;
}
return num2;
}
}
20、剪绳子
# -*- coding:utf-8 -*-
class Solution:
def cutRope(self, number):
# write code here
if number < 2:
return 0
elif number == 2:
return 1
elif number == 3:
return 2
n = number//3
l = number%3
if l == 1:
return int(4*pow(3, (n-1)))
elif l == 2:
return int(pow(3, n)*2)
else:
return int(pow(3, n))
十一:排序专题
1、数组中的第K个最大元素(快排或者堆排序)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def quick_sort(nums, l, r, k):
if (l <=r):
temp = nums[l]
i, j = l, r
while (i != j):
while (i < j and temp < nums[j]):
j -= 1
if (i < j):
nums[i] = nums[j]
i += 1
while (i < j and temp >= nums[i]):
i += 1
if (i < j):
nums[j] = nums[i]
j -= 1
nums[i] = temp
if (i == k - 1):
return temp
elif (i > k-1):
return quick_sort(nums, l, i - 1, k)
else:
return quick_sort(nums, i + 1, r, k)
if(k>len(nums)):
return -1
2、前k个高频元素
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
res_dict={}
res_list=[]
for ele in nums:
if(ele not in res_dict):
res_dict[ele]=1
else:
res_dict[ele]+=1
res=sorted(res_dict.items(),key=lambda x: x[1], reverse=True)
if(k>len(res)):
return []
for index,ele in enumerate(res):
if(index<k):
res_list.append(ele[0])
return res_list
3、根据字符出现频率排序
import collections
class Solution:
def frequencySort(self, s: str) -> str:
m=collections.Counter(s)
tmp=[[k,v] for k,v in m.items()]
tmp.sort(key=lambda x:x[1],reverse=True)
res=''
for ele in tmp:
res=res+ele[0]*ele[1]
return res
4、三种颜色国旗排列
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
low,high=0,len(nums)-1
index=0
while(index<=high):
if(nums[index]==0):
nums[index],nums[low]=nums[low],nums[index]
low+=1
index+=1
elif(nums[index]==1):
index+=1
else:
nums[index],nums[high]=nums[high],nums[index]
high-=1
十二:位运算
1:统计两个数的二进制表示有多少位不同
class Solution(object):
def hammingDistance(self, x, y):
"""
:type x: int
:type y: int
:rtype: int
"""
#所有int型整数都是相同位数
count=0
while(x or y):
if((x & 1) != (y & 1)):
count+=1
x=x>>1
y=y>>1
return count
2:数组中唯一一个不重复的元素
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#交换律:a ^ b ^ c <=> a ^ c ^ b
#任何数于0异或为任何数 0 ^ n => n
#相同的数异或为0: n ^ n => 0
count=0
for ele in nums:
count = count ^ ele
return count
3:找出数组中缺失的那个数
题目描述:数组元素在 0-n 之间,但是有一个数是缺失的,要求找到这个缺失的数。
class Solution(object):
def missingNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res=0
for ele in range(len(nums)+1):
res^=ele
for ele in nums:
res^=ele
return res
4:数组中不重复的两个元素
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
#将数组所有元素进行异或操作
#找出结果的最高位1,两个数中一个最高位是1,一个是0
bit_mask=0
for ele in nums:
bit_mask ^=ele
#找到最高位是1的index
n=len(bin(bit_mask))-3
i,j=0,0
for ele in nums:
if((ele>>n)&1):
i^=ele
else:
j^=ele
return [i,j]
5:判断一个数是不是 2 的 n 次方
class Solution(object):
def isPowerOfTwo(self, n):
"""
:type n: int
:rtype: bool
"""
#n与n-1,如果为0,则是2的幂次方
if(n<=0):
return False
return (n&(n-1))==0
6:判断一个数是不是 4 的 n 次方
class Solution(object):
def isPowerOfFour(self, num):
"""
:type num: int
:rtype: bool
"""
return num >0 and (num & (num-1)==0) and (num & 0xaaaaaaaa)==0
7:判断一个数的位级表示是否不会出现连续的 0 和 1
class Solution(object):
def hasAlternatingBits(self, n):
"""
:type n: int
:rtype: bool
"""
n=(n ^ (n>>1))
n=(n&(n+1))
return n==0
8:数字的补数
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
class Solution(object):
def findComplement(self, num):
"""
:type num: int
:rtype: int
"""
#转换为求掩码过程
#100000000...作为mask与num相与,找出最高位1
mask=1<<30
while((mask & num ==0)):
mask = mask>>1
mask=(mask <<1 )-1
return mask^num
9:字符串数组最大乘积
题目描述:字符串数组的字符串只含有小写字符。求解字符串数组中两个字符串长度的最大乘积,要求这两个字符串不能含有相同字符。
class Solution(object):
def maxProduct(self, words):
"""
:type words: List[str]
:rtype: int
"""
# 或|=:两个二进制对应位只要1个为1,结果就是1,否则是0;
# 与 &=:两个二进制的对应位都为1时,结果为1,否则结果等于0;
# 异或 ^=:两个二进制的对应位不同,结果为1,否则结果为0。
value_list=[0]*len(words)
for i in range(len(words)):
for char_val in words[i]:
#向左移动1
value_list[i] |= 1 << (ord(char_val)-97)
#只要有一个位置相同,&就不必为0
return max([len(words[i])*len(words[j]) for i in range(len(words)) for j in range(i+1,len(words)) if not (value_list[i] & value_list[j])] or [0])
10: 统计从 0 ~ n 每个数的二进制表示中 1 的个数
class Solution(object):
def countBits(self, num):
"""
:type num: int
:rtype: List[int]
"""
#动态规划找规律
#如果是偶数,等于其一半的数中1的数目
#如果是基数,等于其减去一的数中1的数目
res=[0]
for ele in range(1,num+1):
if(ele %2==0):
res.append(res[ele/2])
else:
res.append(res[ele-1]+1)
return res
十三:链表
1、链表反转(迭代 + 头插)
class Solution:
def ReverseList(self , head: ListNode) -> ListNode:
# write code here
# 空链表处理
if head == None:
return head
# 非空链表处理
pre = None
cur = head
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
2、区间内反转
class Solution:
def reverseBetween(self , head: ListNode, m: int, n: int) -> ListNode:
# write code here
p = ListNode(0)
p.next = head # 保证p.next存在
new_head = p
cur = None
i = 1
while i < n:
if i < m:
p = head
head = head.next
elif i >= m:
cur = head.next
head.next = cur.next # 保证第n个节点之后的节点不丢失
cur.next = p.next
p.next = cur
i += 1
return new_head.next
3、 链表中的节点每k个一组翻转
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
class Solution:
def reverseKGroup(self , head: ListNode, k: int) -> ListNode:
# write code here
new_head = ListNode(0)
new_head.next=head
c=0
last=new_head
cur = new_head
while cur:
if c==k:
cur=self.reverse(last,k)
last=cur
c=0
c+=1
cur=cur.next
return new_head.next
def reverse(self, last, k):
queue_head=last.next
for i in range(1, k):
next=queue_head.next
queue_head.next=next.next
next.next=last.next
last.next=next
return queue_head
4、合并两个有序链表
class Solution:
def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
# write code here
h = ListNode(0)
new = h
# 为什么要用new?因为h接下来不断在动,new记住了表头!
while pHead1 and pHead2:
if pHead1.val <= pHead2.val:
h.next = pHead1
pHead1 = pHead1.next
else:
h.next = pHead2
pHead2 = pHead2.next
h = h.next
else:
if pHead1:
h.next = pHead1
elif pHead2:
h.next = pHead2
return new.next
5、K个链表合并
import heapq
class Solution:
def mergeKLists(self , lists: List[ListNode]) -> ListNode:
vhead = ListNode(-1)
p = vhead
heads = [i for i in lists]
heap = [(n.val,idx) for idx, n in enumerate(lists) if n is not None]
heapq.heapify(heap)
while heap:
idx = heapq.heappop(heap)[1] #
tmp = heads[idx]
p.next = tmp
heads[idx] = heads[idx].next
p = p.next
if heads[idx]: heapq.heappush(heap,(heads[idx].val, idx))
return vhead.next
6、链表是否有环(快慢指针,见双指针)
7、链表环的入口 (相遇之后,一个指针指向最开头)
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
if pHead == None:
return None
fast =pHead
slow = pHead
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
break
if fast == None&nbs***bsp;fast.next == None:
return None
slow = pHead
while slow != fast:
slow=slow.next
fast = fast.next
return slow
8、找出倒数最后k个链表节点
class Solution:
def FindKthToTail(self , pHead: ListNode, k: int):
pre = pHead
suc = pHead
for i in range(k):
if suc:
suc = suc.next
else:
return None
while suc:
pre = pre.next
suc = suc.next
else:
return pre
9、删除倒数第n个节点 (先走n步找到该节点)
class Solution:
def removeNthFromEnd(self , head, n):
pre = head
suc = head
for i in range(n):
if suc.next:
suc = suc.next
else:
head = head.next
return head
while suc.next:
pre = pre.next
suc = suc.next
else:
pre.next = pre.next.next
return head
10、两个链表的第一个公共节点
class Solution:
def FindFirstCommonNode(self , pHead1 , pHead2 ):
# 计算链表长度的函数
def lenth(pHead: ListNode):
i = 0
while pHead:
i += 1
pHead = pHead.next
return i
# 走差值
l1 = lenth(pHead1)
l2 = lenth(pHead2)
if l1 >= l2:
n = l1-l2
while n:
pHead1 = pHead1.next
n -= 1
else:
n = l2-l1
while n:
pHead2 = pHead2.next
n -= 1
# 一起走
while pHead1:
if pHead1 == pHead2:
return pHead1
else:
pHead1 = pHead1.next
pHead2 = pHead2.next
# 没有交点返回空
return None
11、两个链表相加
class Solution:
# 反转链表,按照个十百位数顺序相加,carry保存进位数据
# 时间复杂度:O(n) 空间复杂度:O(1)
def reverse_list(self, head):
if not head:
return None
cur = head
pre = None
while cur:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
def addInList(self , head1: ListNode, head2: ListNode) -> ListNode:
if not head1:
return head2
if not head2:
return head1
head1 = self.reverse_list(head1)
head2 = self.reverse_list(head2)
res = ListNode(2022)
head = res
carry = 0
while head1 or head2 or carry != 0:
val1 = 0 if not head1 else head1.val
val2 = 0 if not head2 else head2.val
sum_ = val1 + val2 + carry
carry = sum_ // 10
temp = sum_ % 10
head.next = ListNode(temp)
head = head.next
if head1:
head1 = head1.next
if head2:
head2 = head2.next
return self.reverse_list(res.next)
12、单链表排序
class Solution:
def sortInList(self , head ):
# write code here
list1 = []
while(head):
list1.append(head.val)
head = head.next
list1.sort()
temp = ListNode(0)
pHead = temp
for i in list1:
pHead.next = ListNode(i)
pHead = pHead.next
return temp.next
13、 判断链表是否是回文
class Solution:
def isPail(self , head):
res = []
cur = head
while cur:
res.append(cur.val)
cur = cur.next
return res == res[::-1]
14、 删除有序链表中重复的元素-I
class Solution:
def deleteDuplicates(self , head):
# write code here
cur = head
while cur:
while cur.next and cur.val == cur.next.val:
cur.next = cur.next.next
cur = cur.next
return head
15、删除有序链表中重复的元素-II
class Solution:
def deleteDuplicates(self , head: ListNode) -> ListNode:
# write code here
dummy = pre = ListNode(-1)
while head and head.next:
if head.val == head.next.val:
temp = head.val
while head and head.val == temp:
head = head.next
continue
else:
pre.next = head
pre = pre.next
head = head.next
pre.next = head
return dummy.next
16、二叉树和双向链表
class Solution:
def Convert(self , pRootOfTree ):
# write code here
if not pRootOfTree:return
#建立左子树的双向链表 返回链表头p
left=self.Convert(pRootOfTree.left)
p=left
#定位到左子树的最右节点
while left and p.right:
p=p.right
#假如存在左子树,和根节点连接成双向链表
if left:
p.right=pRootOfTree
pRootOfTree.left=p
#构建右子树的双良链表
right=self.Convert(pRootOfTree.right)
#假如存在柚子树 则和根节点连接成双向链表
if right:
pRootOfTree.right=right
right.left=pRootOfTree
#返回链表
return left if left else pRootOfTree
16、二叉树下一个节点
# -*- coding:utf-8 -*-
# class TreeLinkNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# self.next = None
class Solution:
def GetNext(self, pNode):
# write code here
if not pNode:
return None
if pNode.right: #有右子树
res = pNode.right
while res.left:
res = res.left
return res
while pNode.next: #无右子树,则找第一个当前节点是父节点左孩子的节点
tmp = pNode.next
if tmp.left == pNode:
return tmp
pNode = tmp #沿着父节点向上遍历
return None #到了根节点仍没找到,则返回空