Hot 100 leetcode
笔试整理
8.24 贝壳(四道加起来过了...74%...)
1 动态规划
#吃糖题:
n=5
dp=[0]*(n+1) #记录吃第i颗的最少次数
#dp[i]=min(dp[i],dp[j]+1) if j 到i之间可以一次吃掉
num=[1,1,2,3,4]
if n==1:
print(1)
else:
dp=[0]*(n+1)
for i in range(1,n+1):
dp[i]=i
for j in range(i): #看前面j到i之间的数,是否是2的次方,判断方法不是被2整除!!!
#正确的判断方法: n&(n-1),把最右面的1消除。如果能被2整除,那么一定只有一个1,所以消除后就是0了
arr=num[j:i]
if sum([2**k for k in arr])&(sum([2**k for k in arr])-1)==0:
dp[i]=min(dp[i],dp[j]+1) #如果可以,说明j到i之间的可以一次吃掉,那么就是第j的次数+1
dp[i]=min(dp[i],dp[i-1]+1)
print (dp)
8.24 京东(两道,过了36%)
不难,不要有想法,踏实做吧
#合唱队,给出身高数组,要分组,且满足每组的身高都从小到大递增,并保证分完组整体也满足从小到大递增,
#最多可以分多少组
#看了网上的答案,思路:
#如果i前的最大值,小于或等于i后面的最小值,那么就可以将i前的分为一组(排好序后的最大值小于等后面的最小值)
#一次从前向后遍历,dp_max[i]记录身高中,截止到i目前的最大值,
#一次从后向前遍历,dp_min[i]记录身高中,截止到i的后面最小值是多少。
n=5
num=[2,1,3,2,1]
dp_max=[0]*n
dp_min=[0]*n
maxx=float("-inf")
minn=float("inf")
for i in range(n):
maxx=max(maxx,num[i])
dp_max[i]=maxx
for j in range(n-1,-1,-1):
minn=min(minn,num[i])
dp_min[i]=minn
for i in range(n-1):
if dp_max[i]<=dp_minn[i+1]:
res+=1
print(res)
9.1 腾讯
动态规划(暴力求所有组合过0)
dp[i]表示长度为i时的方案数量=i-k时的方案数(后面k朵全白)+i-1的方案数(最后一朵放红)
dp[i]=dp[i-k]+dp[i-1] , 当i<k时 dp[i-k]=0
1 翻转二叉树
——>
class Solution(object):
def invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if not root:
return
leftnode=root.left #先存储左节点
root.left=self.invertTree(root.right)
root.right=self.invertTree(leftnode)
return root
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def convertBST(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
#二叉搜索树性质:左<中<右
#中序遍历的反向,先右,然后累加给中,然后累加给左
if not root:
return None
node=root
stack=[]
s=0
while node or stack:
while node:
stack.append(node)
node=node.right
node=stack.pop()
s+=node.val #s是从右边开始,每一步都要累加的。
node.val=
3 路径总和 II (广度优先遍历,累计记忆)
class Solution(object):
def pathSum(self, root, summ):
"""
:type root: TreeNode
:type sum: int
:rtype: List[List[int]]
"""
#广度优先遍历BFS(记忆每一个路径上的数,累计记忆)
#新的结构 [(Node,[node1.val,node2.val,...])] #set里面节点与节点前路径上的所有值
if not root:
return []
stack=[(root,[root.val])]
res=[]
for i,j in stack:
if not i.left and not i.right and sum(j)==summ:
res.append(j)
if i.left:
copy_j=j[:]
copy_j.append(i.left.val)
stack.append((i.left,copy_j))
if i.right:
copy_j=j[:]
copy_j.append(i.right.val)
stack.append((i.right,copy_j))
return res
"""
#回溯
res=[]
def dfs(root,temp,sumnum):
if not root.left and not root.right and sumnum==root.val:
temp.append(root.val)
res.append(temp[:])
return
if root.left:
dfs(root.left,temp+[root.val],sumnum-root.val)
if root.right:
dfs(root.right,temp+[root.val],sumnum-root.val)
if not root:
return []
dfs(root,[],summ)
return res
"""
4 路径总和 III
class Solution(object):
def pathSum(self, root, summ):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
self.count=0
def dfs(root,temp):
if not root:
return
temp.append(root.val)
cur=0
for i in range(len(temp)-1,-1,-1): #从后往前,检查以root.val结尾的解的个数
cur+=temp[i]
if cur==summ:
self.count+=1
dfs(root.left,temp)
dfs(root.right,temp)
temp.pop() #回溯,还原当前值
dfs(root,[])
return self.count
"""
#超时,过了90%,
def dfs(root,temp,sumnum):
if not root:
return
if sumnum==root.val:
temp.append(root.val)
res.append("->".join(str(s) for s in temp[:]))
#return
#if root.left:
dfs(root.left,temp+[root.val],sumnum-root.val)
#if root.right:
dfs(root.right,temp+[root.val],sumnum-root.val)
if not root:
return 0
stack=[root]
al=[root] #记录所有节点
res=[] #记录所有路径
while stack:
temp=[]
leng=len(stack)
for i in range(leng):
if stack[i].left:
temp.append(stack[i].left)
if stack[i].right:
temp.append(stack[i].right)
stack=temp
if temp:
al.extend(temp)
for node in al:
dfs(node,[],summ)
return len(res)
"""
"""
def pathSum(self, root, summ):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
#广度优先遍历,超时
if not root:
return 0
stack=[(root,[root.val])]
res=[]
for i,j in stack:
c=0
for k in range(len(j)-1,-1,-1): #以该节点结尾的所有路径
c+=j[k]
if c==summ:
res.append("->".join(str(s) for s in j[k:]))
if i.left:
copy_j=j[:]
copy_j.append(i.left.val)
stack.append((i.left,copy_j))
if i.right:
copy_j=j[:]
copy_j.append(i.right.val)
stack.append((i.right,copy_j))
return len(res)
"""
5 最小栈
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack1=[]
self.stack2=[]
def push(self, x):
"""
:type x: int
:rtype: None
"""
#stack2存储最小值。每次比较新加入的值和栈顶值,添加最小的进栈
self.stack1.append(x)
if not self.stack2:
self.stack2.append(x)
else:
temp=self.stack2[-1]
if x<temp:
self.stack2.append(x)
else:
self.stack2.append(temp)
def pop(self):
"""
:rtype: None
"""
if not self.stack1:
return "empty error"
self.stack2.pop() #pop记得将最小值栈也pop
return self.stack1.pop()
def top(self):
"""
:rtype: int
"""
return self.stack1[-1] if self.stack1 else "empty error"
def getMin(self):
"""
:rtype: int
"""
return self.stack2[-1]
6 二叉树的直径
class Solution(object):
def diameterOfBinaryTree(self, root):
"""
:type root: TreeNode
:rtype: int
"""
self.max=0
self.diameter(root)
return self.max
def diameter(self, root):
#层次遍历,获得左子树最大深度h1,还有右子树最大深度h2,返回 h1+h2
#但容易忽略特殊情况,最长路径在一侧,所以是每个节点作为根节点的左右深度和,求最大值
if not root:
return
h1=self.depth(root.left,0)
h2=self.depth(root.right,0)
self.max=max(self.max,h1+h2)
self.diameter(root.left) #左右子树都要递归判断
self.diameter(root.right)
#层次遍历求深度
def depth(self,root,h):
if root:
stack=[root]
while stack:
leng=len(stack)
temp=[]
for i in range(leng):
if stack[i].left:
temp.append(stack[i].left)
if stack[i].right:
temp.append(stack[i].right)
h+=1
stack=temp
return h
"""
self.max=0
self.depth(root)
return self.max
#递归求深度:
def depth(self,root):
if not root:
return 0
l=self.depth(root.left)
r=self.depth(root.right)
self.max=max(self.max,l+r)
return max(l,r)+1
"""
7 回文链表
找到中点->反转后半部分->遍历比较前后两个链表
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
#找到中点
fast,slow=head,head
while fast and fast.next:
fast=fast.next.next
slow=slow.next
#反转后半部分
mid=slow
pre=None
while mid:
nex=mid.next
mid.next=pre
pre=mid
mid=nex
#pre是后半部分反转后的头节点
while pre:
if pre.val!=head.val: #比较的值是否一样,记得加val!!!
return False
pre=pre.next
head=head.next
return True
8 找到字符串中所有字母异位词(滑动窗口思想)
滑动窗口思想:右侧窗口不断右移加入元素,当个数等于p的长度时,判断里面各元素是否相等。若相等:则添加左边index,无论是否相等,到达长度都要左侧右移,更新窗口内的left(windows[s[left]]-=1)。右侧窗口继续右移。
from collections import Counter
d=Counter(s) 直接获得字符串s的统计字符及其个数的字典
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
#滑动窗口思想
window={}
need={}
for i in p:
need[i]=need.get(i,0)+1
res=[]
l=r=0
while r<len(s):
temp=s[r]
if temp not in need: #不存在与p,则清除窗口
window={}
l=r+1
r=r+1
else:
window[temp]=window.get(temp,0)+1
if r-l+1==len(p): #若长度达到要求
if window==need: #若找到,则加入res,左侧左移,更新窗口值
res.append(l)
window[s[l]]-=1 #无论是否找到,都要左移,更新窗口值
l+=1
r+=1
return res
#方法2,暴力
"""
#O(len(s)*len(p))超时
leng=len(p)
d=Counter(p)
res=[]
for k in range(len(s)-leng+1):
if self.judge(s[k:k+leng],d):
res.append(k)
else:
continue
return res
#每次查看是否相等
def judge(self,s,d):
t1=Counter(s)
for i in d:
if i not in t1 or t1[i]!=d[i]:
return False
return True
"""
9 无重复字符的最长子串(滑动窗口)
窗口window是字典,记录元素的index位置。右面依次右移,如果遇到重复的,更新长度,找到上一个重复的位置index,将index前的window全部清除(这里直接全部清除),将左侧和右侧重新定位在index+1,:如“tmmxbat”。然后继续右移。
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
#用切片
l=[]
res=[]
for i in range(len(s)):
if s[i] not in l:
l.append(s[i])
res.append(len(l))
else:
index=l.index(s[i])
l=l[index+1:] #更新子串,将重复的及之前的清理掉
l.append(s[i])
res.append(len(l)) #abbbcdef的情况,最长的在最后
return max(res)
"""
#滑动窗口
if not s:
return 0
window={} #记录元素的index值
res=1
left=right=0
while right<len(s):
temp=s[right]
if temp not in window: #若窗口内没有重复值
window[temp]=right #存储index
res=max(res,right-left+1) #避免一直没有重复的情况,所以也要更新一下 如abcd
else: #窗口内存在重复值
res=max(res,right-left) #更新窗口最大长度,该重复值不算,所以窗口长度要-1
index=window[temp] #找到上一个重复值的位置
left=right=(index+1)
window.clear() #将index前的全部清理,防止后面再次查询到 ,如 "tmmzuxt"
window[s[left]]=right #将新window的第一个字符加入window
right+=1
return res
"""
def findUnsortedSubarray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#两次遍历,左到右,找到右边界(比其左边最大值要小的),右到左,找到左边界(比其右边最小值还要大的)
L=0
R=0
maxx=nums[0]
minn=nums[-1]
for i in range(len(nums)):
if nums[i]<maxx:
R=i
maxx=max(maxx,nums[i])
for j in range(len(nums)-1,-1,-1):
if nums[j]>minn:
L=j
minn=min(minn,nums[j])
return R-L+1 if R>L else 0 #如果没有乱序的,则L=R=0
"""
#排序后,双指针前后对比
arr=sorted(nums)
leng=len(nums)
i=0
j=leng-1
while i<leng and nums[i]==arr[i]:
i+=1
while j>=0 and nums[j]==arr[j]:
j-=1
return j-i+1 if j>i else 0
"""
11 每日温度
def dailyTemperatures(self, T):
"""
:type T: List[int]
:rtype: List[int]
"""
#记录,后入栈的元素values与栈顶元素s比较:
#若value>s,则说明栈顶元素s找到了比其大的值,记录下标之差,然后依次出栈
#若value<=s,则直接入栈,待寻找
stack=[]
res=[0]*len(T)
for i in range(len(T)):
if stack:
while stack and T[stack[-1]]<T[i]:
res[stack[-1]]=i-stack[-1]
stack.pop()
stack.append(i)
return res
"""
#暴力,超时
res=[]
for i in range(len(T)):
temp=T[i]
j=i+1
while j<len(T) and T[j]<=temp:
j+=1
if j==len(T):
res.append(0)
else:
res.append(j-i)
return res
"""
12 688. “马”在棋盘上的概率(回溯+记忆)
class Solution(object):
def knightProbability(self, N, K, r, c):
"""
:type N: int
:type K: int
:type r: int
:type c: int
:rtype: float
"""
#三:记忆+回溯,记录已经走过的概率,再碰到就直接返回该点的概率
mem={}
dic=[[2,1],[2,-1],[1,2],[1,-2],[-2,1],[-2,-1],[-1,2],[-1,-2]]
def f(x,y,k):
#记忆化搜索
if (x,y,k) in mem:
return mem[(x,y,k)]
if k==K:
return 1
p=0
for dx,dy in dic:
if N>x+dx>=0 and N>y+dy>=0:
p+=f(x+dx,y+dy,k+1)
else:
continue
p/=8.0
mem[(x,y,k)]=p
return p
return f(r,c,0)
"""
#一:层次遍历,最后一层的个数就是所有的路径数
dic=[[2,1],[2,-1],[1,2],[1,-2],[-2,1],[-2,-1],[-1,2],[-1,-2]]
count=0
stack=[[r,c]]
i=0
while i<K:
temp=[]
for x,y in stack:
for dx,dy in dic:
if N>x+dx>=0 and N>y+dy>=0:
temp.append([x+dx,y+dy])
stack=temp
i+=1
count=len(stack)
return count/float(8**K)
#二:暴力回溯方法,超时,11/21
dic=[[2,1],[2,-1],[1,2],[1,-2],[-2,1],[-2,-1],[-1,2],[-1,-2]]
self.res=0
def f(x,y,k):
if k==K:
self.res+=1
return
for dx,dy in dic:
if N>x+dx>=0 and N>y+dy>=0:
f(x+dx,y+dy,k+1)
else:
continue
f(r,c,0)
return self.res/float(8**K)
"""
13 一和零
01背包问题(但是是多维的,不仅满足体积,还要满足质量)
外面物品循环,里面是逆序的质量和体积的双重循环 dp[i][j]=max( dp[i] [j], 1+dp [i-count_0] [j-count_1] )
def findMaxForm(self, strs, m, n):
"""
:type strs: List[str]
:type m: int
:type n: int
:rtype: int
"""
numss=[]
for s in strs:
temp=[int(i) for i in s]
numss.append(temp)
#动态规划,01背包问题,二维的,既要满足0又要满足1
dp=[[0] *(m+1) for t in range(n+1)] #列m 行n
#01背包,物品在外面,里面倒叙
for num in numss:
one=0
zero=0
for i in num:
if i==0:zero+=1
else:one+=1
for j in range(n,one-1,-1):
for k in range(m,zero-1,-1):
dp[j][k]=max(dp[j][k],dp[j-one][k-zero]+1)
return dp[n][m]
"""
统计字符串中某个字符的 个数: ss.count("s")
"""