这里写目录标题
- 第一章 字符串相关问题II
- 1、Leetcode 387:字符串中的第一个唯一字符
- 2、Leetcode 8:字符串转换整数重写
- 3、Leetcode 541:反转字符串II重写
- 4、Leetcode 151:翻转字符串里的单词重写
- 5、Leetcode 537:反转字符串中的单词iii重写
- 6、Leetcode 917:仅反转字母重写
- 7、Leetcode 438:找到字符串中所有字母异位词重写
- 8、Leetcode 5:最长回文串重写
- 9、Leetcode 205:同构字符串
- 10、Leetcode 680:验证回文字符串II重写
- 11、Leetcode 44:通配符匹配重写
- 12、Leetcode 32:最长有效括号重写
- 13、Leetcode 115:不同的子序列重写
- 第二章 高级动态规划
- 第三章 布隆过滤器&LRU cache
- 第三章 位运算
第一章 字符串相关问题II
1、Leetcode 387:字符串中的第一个唯一字符
题目描述
解题思路
使用哈希表,key存储字符,value存储对应下标。
代码实现
class Solution:
def firstUniqChar(self, s: str) -> int:
#建立哈希表
dic=collections.defaultdict(list)
for i in range(len(s)):
dic[s[i]].append(i)
#遍历哈希表找到第一个次数为1的
for k,v in dic.items():
if len(v)==1:
return int(v[-1])
return -1
2、Leetcode 8:字符串转换整数重写
class Solution:
def myAtoi(self, s: str) -> int:
#对字符串左边的空格进行处理
slices=list(s.strip())
#如果为空,返回0
if len(slices)==0:
return 0
#先判断正负号
signal = -1 if slices[0]=="-" else 1
#将正负号删除
if slices[0] in ["-","+"]: del slices[0]
res,i=0,0
#开始循环
while i < len(slices) and slices[i].isdigit():
res=res*10+ord(slices[i])-ord("0")
i+=1
return max(min(2**31-1,res*signal),-2**31)
3、Leetcode 541:反转字符串II重写
class Solution:
def reverseStr(self, s: str, k: int) -> str:
n=len(s)
li=list(s)
for i in range(0,n,k*2):
li[i:i+k]=li[i:i+k][::-1]
return "".join(li)
4、Leetcode 151:翻转字符串里的单词重写
class Solution:
def reverseWords(self, s: str) -> str:
#切片
word_list=s.split()
word_list.reverse()
return " ".join(word_list)
5、Leetcode 537:反转字符串中的单词iii重写
class Solution:
def reverseWords(self, s: str) -> str:
n=len(s)
#切片
word_list=[list(word) for word in s.split()]
#遍历
res=[]
for word in word_list:
word.reverse()
res.append("".join(word))
return " ".join(res)
6、Leetcode 917:仅反转字母重写
class Solution:
def reverseOnlyLetters(self, S: str) -> str:
#将输入中纯字母的压栈
stack=[char for char in S if char.isalpha()]
#开始修改原始字符串
li=list(S)
for i in range(len(li)):
if S[i].isalpha():
new_char=stack.pop()
li[i]=new_char
else:
continue
return "".join(li)
7、Leetcode 438:找到字符串中所有字母异位词重写
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
#长度
m,n=len(s),len(p)
res=[]
#特殊条件
if m<n:
return []
#建立一个26位列表的映射
p_save=[0]*26
s_save=[0]*26
#对于s中的前n个数字进行添加
for i in range(n):
p_save[ord(p[i])-ord("a")]+=1
s_save[ord(s[i])-ord("a")]+=1
#判断
if p_save==s_save:
res.append(0)
#开始从下标为n开始遍历
for j in range(n,m):
#新添加的
s_save[ord(s[j])-ord("a")]+=1
#去除的
s_save[ord(s[j-n])-ord("a")]-=1
#判断
if s_save==p_save:
res.append(j-(n-1))
return res
8、Leetcode 5:最长回文串重写
class Solution:
def expand_valid(self,s,left,right):
while left>=0 and right<len(s) and s[left]==s[right]:
left-=1
right+=1
return left+1,right-1
def longestPalindrome(self, s: str) -> str:
start,end=0,0
for i in range(len(s)):
l1,r1=self.expand_valid(s,i,i)
l2,r2=self.expand_valid(s,i,i+1)
#判断
if r1-l1>end-start:
start,end=l1,r1
if r2-l2>end-start:
start,end=l2,r2
return s[start:end+1]
9、Leetcode 205:同构字符串
题目描述
解题思路
两个字典存储s和t每个单词出现的对应得下标位置,如果同构,他们的字典中的下标位置的存储一定相同,很简单。
代码实现
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
n=len(s)
dic_s=collections.defaultdict(list)
dic_t=collections.defaultdict(list)
for i in range(n):
dic_s[s[i]].append(i)
dic_t[t[i]].append(i)
li1=[v for k,v in dic_s.items()]
li2=[v for k,v in dic_t.items()]
return li1==li2
10、Leetcode 680:验证回文字符串II重写
class Solution:
def valid_str(self,s,left,right):
while left<right:
if s[left]==s[right]:
left+=1
right-=1
else:
return False
return True
def validPalindrome(self, s: str) -> bool:
low,high=0,len(s)-1
while low<high:
if s[low]==s[high]:
low+=1
high-=1
else:
return self.valid_str(s,low+1,high) or self.valid_str(s,low,high-1)
return True
11、Leetcode 44:通配符匹配重写
class Solution:
def isMatch(self, s: str, p: str) -> bool:
#长度
m,n=len(s),len(p)
#建立dp
dp=[[False]*(n+1) for _ in range(m+1)]
dp[0][0]=True
#初始化
for i in range(1,n+1):
if p[i-1]=="*":
dp[0][i]=True
else:
break
#开始遍历
for i in range(1,m+1):
for j in range(1,n+1):
if p[j-1]=="*":
dp[i][j]=dp[i][j-1]|dp[i-1][j]
elif p[j-1]=="?" or s[i-1]==p[j-1]:
dp[i][j]=dp[i-1][j-1]
return dp[-1][-1]
12、Leetcode 32:最长有效括号重写
class Solution:
def longestValidParentheses(self, s: str) -> int:
#长度
n=len(s)
#特殊条件
if n==0:
return 0
#建立dp
dp=[0]*n
#无边际条件,0就是0
#开始遍历
for i in range(1,n):
#当前位置是右括号时
if s[i]==")":
if s[i-1]=="(":
dp[i]=dp[i-2]+2
elif s[i-1]==")" and i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=="(":
dp[i]=dp[i-1]+dp[i-dp[i-1]-2]+2
return max(dp)
13、Leetcode 115:不同的子序列重写
class Solution:
def numDistinct(self, s: str, t: str) -> int:
#统计长度
m,n=len(s),len(t)
if m<n:
return 0
#建立dp
dp=[[0]*(n+1) for _ in range(m+1)]
#当t为空时可以匹配所有
for i in range(m+1):
dp[i][n]=1
#开始遍历,反向
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
#如果当前相等
if s[i]==t[j]:
#可以选择匹配或者不匹配
dp[i][j]=dp[i+1][j]+dp[i+1][j+1]
else:
#只能不匹配
dp[i][j]=dp[i+1][j]
return dp[0][0]
第二章 高级动态规划
1、Leetcode 300:最长递增子序列重做
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
#长队
n=len(nums)
#定义dp
dp=[1]*n
#开始循环
for i in range(n):
for j in range(i):
if nums[j]<nums[i]:
dp[i]=max(dp[i],dp[j]+1)
return max(dp)
2、Leetcode 91:解码方法重做
class Solution:
def numDecodings(self, s: str) -> int:
#长度
n=len(s)
#建立dp
dp=[0]*(n+1)
#特殊条件
if s[0]=="0":
return 0
#初始化
dp[0],dp[1]=1,1
#开始循环
for i in range(1,n):
#如果当前不为0
if s[i]!="0":
#它自己就可以被解码
dp[i+1]=dp[i]
#还要考虑两个相邻的
nums=10*(ord(s[i-1])-ord("0"))+ord(s[i])-ord("0")
if 10<=nums<=26:
dp[i+1]+=dp[i-1]
return dp[-1]
3、Leetcode 32:最长有效括号重写
class Solution:
def longestValidParentheses(self, s: str) -> int:
#长度
n=len(s)
dp=[0]*(n)
#特殊条件
if n==0:
return 0
#开始循环
for i in range(1,n):
if s[i]==")":
if s[i-1]=="(":
dp[i]=dp[i-2]+2
elif s[i-1]==")" and i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=="(":
dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2]
return max(dp)
4、Leetcode 85:最大矩形
题目描述
解题思路
- 使用pre存储对于每一行来说,底为1的数量
- 使用单调栈不断的把pre中的数量排序排号,当当前栈中最后一个位置索引对应的1的数量大于了当前循环位置的为1的数量P时,说明栈中以末尾索引O为基础,剩下的k-O-1个位置的储存1的数量都大于当前数量P,所以以k-O-1为长,P为高的矩形可找到,计算一次面积,不断更新最大的面积,最后返回。
代码实现
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
#特殊情况
if not matrix: return 0
#行列的长度
m,n=len(matrix),len(matrix[0])
#建立pre
pre=[0]*(n+1)
res=0
#开始填充前缀和
for i in range(m):
for j in range(n):
pre[j]=pre[j]+1 if matrix[i][j]=="1" else 0
#每一层的单调栈
stack=[-1]
#遍历pre的索引和值
for k,num in enumerate(pre):
while stack and pre[stack[-1]]>num:
index=stack.pop()
res=max(res,pre[index]*(k-stack[-1]-1))
stack.append(k)
return res
5、Leetcode 115:不同的子序列重写
class Solution:
def numDistinct(self, s: str, t: str) -> int:
#长度
m,n=len(s),len(t)
#特殊条件,当s的长度小于t,不可能存在解
if m<n:
return 0
#建立dp
dp=[[0]*(n+1) for _ in range(m+1)]
#特殊条件,当t为空时,它可以满足所有的s的长度
for i in range(1,m+1):
dp[i][n]=1
#开始循环
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
#如果当前i和j对应的相同
if s[i]==t[j]:
#可以选择添加或者不添加
dp[i][j]=dp[i+1][j]+dp[i+1][j+1]
else:
#只能不要j
dp[i][j]=dp[i+1][j]
return dp[0][0]
6、Leetcode 818:赛车
题目描述
解题思路
这道题找到了一个解释的很清楚的题解
代码实现
class Solution:
def racecar(self, target: int) -> int:
#建立dp
dp=[float("inf")]*(target+1)
#开始循环
for i in range(1,target+1):
#A的次数
k=1
pos=1
#当目前的pos小于i,且往回走
while pos<i:
#倒车转向后A的次数
q=0
while (1<<q)-1<pos:
dp[i]=min(dp[i],k+1+q+1+dp[i-(pos-((1<<q)-1))])
q+=1
k+=1
pos=(1<<k)-1
#当i等于pos,那就是全为a
if i==pos:
dp[i]=k
#如果超出了就往回走,+1是要代表R
else:
dp[i]=min(dp[i],k+1+dp[pos-i])
return dp[target]
第三章 布隆过滤器&LRU cache
Leetcode 146:LRU缓存机制
题目描述
代码实现
orderdic实现哈希和双向链表
class LRUCache:
def __init__(self, capacity: int):
#建立一个orderdic
self.dic=collections.OrderedDict()
#定义容量
self.remain=capacity
def get(self, key: int) -> int:
#如果不在dic中,直接返回-1
if key not in self.dic:
return -1
#如果在的话,先把它pop出来
v=self.dic.pop(key)
#放到首端
self.dic[key]=v
return v
def put(self, key: int, value: int) -> None:
#如果当前key已经在lru中
if key in self.dic:
#拿出来
self.dic.pop(key)
else:
#如果当前容量未满
if self.remain>0:
self.remain-=1
#如果满了,就要把第一个pop出来
else:
self.dic.popitem(last=False)
#添加元素
self.dic[key]=value
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
第三章 位运算
1、Leetcode 191:位1的个数
题目描述
代码实现
方法一:不断清零最低位的1
class Solution:
def hammingWeight(self, n: int) -> int:
count=0
while n>0:
#清零最低位的1
n=n&(n-1)
count+=1
return count
方法二:调用bin函数:将int转为二进制表示
class Solution:
def hammingWeight(self, n: int) -> int:
return bin(n).count("1")
方法三:循环检查
class Solution:
def hammingWeight(self, n: int) -> int:
count=0
for num in bin(n):
if num=="1":
count+=1
return count
方法四:位运算不断右移动
class Solution:
def hammingWeight(self, n: int) -> int:
count=0
while n:
#如果当前最后一位为1
count+=n&1
#x右移动一位
n=n>>1
return count
2、Leetcode 231:2的幂
题目描述
代码实现
方法一:循环统计
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
if n<0:
return False
count=0
for num in bin(n):
if num=="1":
count+=1
return True if count==1 else False
方法2:不断除2看是否可以除进
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
if n<=0:
return False
while n%2==0:
n/=2
return n==1
方法3:使用x&(-x)
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
if n ==0:
return False
return n&(-n)==n#n&(-n):保留n中的最低位的1,其余归0
3、 Leetcode 190:颠倒二进制位
题目描述
解题思路
n&1可以返回当前最右边位置是1还是0,将这个位置左移动31位就是它该出现的颠倒后的位置,对于右边第二位,因为右边第一位已经处理好了,那么直接把n右移动一位,然后还是判断n&1的值,再左移动30位即可,如此循环,直到n为0
代码实现
class Solution:
def reverseBits(self, n: int) -> int:
res,idx=0,31
while n:
res+=(n&1)<<idx#看n最右边的是1还是0,左移动31-i位数
n=n>>1#n向右移动一次
idx-=1#更新idx
return res
4、Leetcode 51:N皇后问题的位运算解法
代码实现
dfs方法
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
#定义一个存储输出结果的列表
res=[]
#定义数组存储棋子的pie、na、col的信息
col,pie,na=set(),set(),set()
#建立递归函数
def dfs(n,row,state):
#终止条件
if row==n:
res.append(state)
#当前层的处理
for cols in range(n):#遍历当前层的每一个列
#判断当前位置是否符合规定
if cols in col or cols+row in pie or row-cols in na:
continue
#将当前信息加入三个集合
col.add(cols)
pie.add(cols+row)
na.add(row-cols)
#进入下一层循环
dfs(n,row+1,state+[cols])
#出循环后remove掉
col.remove(cols)
pie.remove(cols+row)
na.remove(row-cols)
def generated_result(n):
#建立一个空列表
board=[]
#拿出res的每一个state
for state in res:
#拿出state中每一行的信息
for col_pos in state:
board.append("."*col_pos+"Q"+"."*(n-col_pos-1))
#返回结果
return [board[i:i+n] for i in range(0,len(board),n)]
dfs(n,0,[])
return generated_result(n)
位运算方法
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
res=[]
def generated_result():
board=[]
for i in range(n):
row[queen[i]]="Q"
board.append("".join(row))
row[queen[i]]="."
return board
def dfs(row,columns,pie,na):
#终止条件:
if row==n:
board=generated_result()
res.append(board)
else:
#将所有可以放置的地方置为1
possible=((1<<n)-1)&(~(columns|pie|na))
#开始循环所有可能放置的位置
while possible:
position=possible&(-possible)#拿到最右边可以放置的位置
#将该位置清零
possible=possible&(possible-1)
#找到为1的位置
column=bin(position-1).count("1")
queen[row]=column
#进入下一层
dfs(row+1,columns|position,(pie|position)<<1,(na|position)>>1)
#存储每一行皇后的所在列位置
queen=[-1]*n
row=["."]*n
dfs(0,0,0,0)
return res
5、Leetcode 52:N皇后ii
返回的是一共有多少种可能
代码实现
方法一:dfs
class Solution:
def totalNQueens(self, n: int) -> int:
#定义三个集合
column,pie,na=set(),set(),set()
#递归
def dfs(n,row):
#终止条件:
if row==n:
return 1
else:
count=0
for col in range(n):
if col in column or col+row in pie or row-col in na:
continue
#添加
column.add(col)
pie.add(col+row)
na.add(row-col)
count+=dfs(n,row+1)
column.remove(col)
pie.remove(col+row)
na.remove(row-col)
return count
return dfs(n,0)
方法二:位运算
class Solution:
def totalNQueens(self, n: int) -> int:
def dfs(row,column,pie,na):
if row==n:
return 1
else:
count=0
#拿到当前层所有可能的位置
possible=((1<<n)-1)&(~(column|pie|na))
while possible:
#拿到最右边为1的值
postion=possible&(-possible)
#将该位置变为0
possible=possible&(possible-1)
#进入下一层
count+=dfs(row+1,column|postion,(pie|postion)<<1,(na|postion)>>1)
return count
return dfs(0,0,0,0)
6、Leetcode 338:比特位计数
题目描述
代码实现
循环的方法
class Solution:
def countBits(self, num: int) -> List[int]:
def solve(x):
count=0
while x>0:
#将最低位的1变为0
x=x&(x-1)
count+=1
return count
return [solve(i) for i in range(num+1)]
位运算方法
class Solution:
def countBits(self, num: int) -> List[int]:
res=[0]*(num+1)
res[0]=0
high_bit=0
for i in range(1,num+1):
#如果当前i是2的某次幂
if i&(i-1)==0:
high_bit=i
res[i]=res[i-high_bit]+1
return res