41、 缺失的第一个正数
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
解:先排序,然后从第一个大于零的数nums[i]开始往前走,如果它大于1,就返回一,否则不断+1,如果后面的数是前面的+1或+0,继续,否则输出前面的数+1即可。
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
if not nums:
return 1
nums.sort()
n=len(nums)
index=0
for i in range(n):
if nums[i]>0:
index=i
break
if nums[index]<=0:
return 1
if nums[index]>1:
return 1
if index==n-1:
return 2
i=index+1
while i<n and (nums[i]==nums[i-1]+1 or nums[i]==nums[i-1]):
i=i+1
return nums[i-1]+1
执行用时:40 ms, 击败了76.27%的用户
内存消耗:13.7 MB, 击败了48.93%的用户
42、接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
还是用类似双指针的办法,显示让i=0,j向后走直到height[j]>=height[i],如果j-i>1则可以计算,更新i=j。如果j循环完之后发现i!=n-1,那么说明i是最大的那个,这时就要改变思路,每次都找i后面最大的那个坐标index,它可以和i一起装水,再更新i=index并重复操作直到i=n-1。
class Solution:
def trap(self, height: List[int]) -> int:
ways=[]
i=0
total=0
n=len(height)
if not height or len(height)<=2:
return 0
for j in range(1,n):
if height[j]>=height[i] and j-i>1:
if height[i]>0:
for k in range(i+1,j):
total=total+height[i]-height[k]
i=j
else:
i=j
elif height[j]>=height[i]:
i=j
while i<len(height)-1:
j=self.findHighestofRest(i,height)
if j-i>1:
for k in range(i+1,j):
total=total+height[j]-height[k]
i=j
return total
def findHighestofRest(self,index,height):
lastheight=index+1
if index+2==len(height):
return index+1
else:
for k in range(index+2,len(height)):
if height[k]>=height[lastheight]:
lastheight=k
return lastheight
执行用时:44 ms, 击败了88.95%的用户
内存消耗:14.1 MB, 中击败了63.45%的用户
43、字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
class Solution:
def multiply(self, num1: str, num2: str) -> str:
adict={"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}
ans=0
n=len(num1)
m=len(num2)
for i in range(n-1,-1,-1):
for j in range(m-1,-1,-1):
ans=ans+adict[num1[i]]*adict[num2[j]]*(10**(n+m-2-i-j))
return str(ans)
解:此问题就是让模拟乘法运算,只要做双循环即可。
执行用时:200 ms击败了36.58%的用户
内存消耗:13.7 MB击败了52.81%的用户
44、通配符匹配
给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *
解:与第10题正则表达式的匹配类似,但是在本题中p的任意一个字符都是相互独立的。在本题中*
的取值是不确定的,需要进行枚举,这时可以考虑用动态规划来减少枚举的次数。dp[i][j]表示s[0:i]与p[0:i]是否匹配。
在考虑状态转移时:
如果pj是字母,那么si必须是与其相等的字母且dp[i-1][j-1]=True
如果pj是问号,那么si只需是一个字母,且dp[i-1][j-1]=True
如果pj是*,那么对si没有任何要求只需分用还是不用这个*
,用的话就是dp[i-1][j]为True,不用的话就是dp[i][j-1]为True。两者只要有一个成立即可。
边界条件dp[0][0]为True,dp[0][j]只有当p的前j个都为时才成立,也就是说dp[0][j]为True当且仅当dp[0][j-1]为True且p[j-1]为。dp[i][0]为false
所以递推应该按照i+j=k,k=0,1,2,…的形式递推。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m=len(s)
n=len(p)
dp=[[False for i in range(n+1)] for j in range(m+1)]
dp[0][0]=True
for i in range(1,n+1):
if p[i-1]=='*'and dp[0][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-1][j] | dp[i][j-1]
elif p[j-1]=='?' or p[j-1]==s[i-1]:
dp[i][j]=dp[i-1][j-1]
return dp[m][n]
执行用时:928 ms, 击败了56.48%的用户
内存消耗:21.8 MB, 击败了52.73%的用户
45、跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
解:用BFS就可以了,如果一个点能到另一个点就连边,从而构成一个有向无圈图。
class Solution:
def jump(self, nums: List[int]) -> int:
n=len(nums)
gray=[]#已发现但还未探查
black=[]#已经探查完毕
distance={}#存储各点到0的距离
distance[0]=0
gray.append(0)
if not nums or n==1:
return 0
while gray:
a=gray.pop()
for i in range(1,nums[a]+1):
if i+a==n-1:
return distance[a]+1
if (i+a<n) and (i+a not in black) and (i+a not in gray):
gray.insert(0,i+a)
distance[i+a]=distance[a]+1
black.append(a)
然而该方法会超出时间限制
可以对BFS进行初步的改进。注意到由于在本题中搜索是顺序进行的,不会重复,因此可以把black删去,此外还可以在每次遍历的时候先遍历大的元素,从而更快的到达n-1。
class Solution:
def jump(self, nums: List[int]) -> int:
n=len(nums)
gray=[]
distance={}
distance[0]=0
gray.append(0)
if not nums or n==1:
return 0
while gray:
a=gray.pop()
for i in range(nums[a],0,-1):
if a+i==n-1:
return distance[a]+1
if a+i not in gray:
distance[a+i]=distance[a]+1
gray.insert(0,a+i)
执行用时:3288 ms, 击败了5.04%的用户
内存消耗:18.7 MB, 击败了5.07%的用户
解法二:我们可以对上述的BFS进行合理化改进,以节约内存和时间。我们可以用lastmax代表上一次查到的最大距离,也就是再gray里的元素,往gray里添加新元素也不用逐个添加,而是找出上一次添加元素能够走出的最大距离。
用i代表上一次能够探索到的最大距离的元素(上次探索从i出发可以探索到最大的距离),下一次只要遍历(i+1,i+1+nums[i])即可找到下一次能探索到的最大距离,并记下相应点
class Solution:
def jump(self, nums: List[int]) -> int:
n=len(nums)
step=i=maxLen = 0
while i<n:
if i>=n-1:
return step
step=step+1 #新加一次,再上次探索过的基础上
for j in range(i+1,i+1+nums[i]):#
if j>=n-1:
return step
if maxLen<nums[j]+j:
maxLen = nums[j]+j
temp=j
i = temp
执行用时:52 ms, 在所有 Python3 提交中击败了83.91%的用户
内存消耗:15.2 MB, 在所有 Python3 提交中击败了40.76%的用户