剑指offer59 - II 至 剑指offer 64 题解
Posted 风去幽墨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer59 - II 至 剑指offer 64 题解相关的知识,希望对你有一定的参考价值。
剑指 Offer 59 - II. 队列的最大值
题意:
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
题解:
解法1:暴力(240ms)
队列的插入删除就使用原有队列的插入删除操作,查询最大值时暴力查找。
解法2:队列+双向队列(324ms)
一个普通队列用来正常存放元素,并进行插入删除操作,另一个双向队列用来记录最大值。双向队列的维护要求:
- 内部非递增,插入数据时,从双向队列尾部取出比当前值小的元素,来达到非递增的要求
- 删除时,根据普通队列删除的元素于双向队列的头部元素进行比较,若相同则删除掉双向队列的头部元素。
解法3:小顶堆(232ms)
使用两个小顶堆,一个小顶堆A用于存放当前队列的最大值,另一个小顶堆B用于存放当前队列中已被删除但在小顶堆A中未被删除的所有元素。
- 插入时,向普通队列和小顶堆A同时插入
- 查询最大值时,若是堆A与堆B头部元素相同,则表明当前元素应该已被删除,while循环直至两者不同
- 删除时,普通队列直接删除,并向堆B中插入被删除元素。
代码:
#法1
import queue
class MaxQueue:
def __init__(self):
self.deque = queue.deque()
def max_value(self) -> int:
return max(self.deque) if self.deque else -1
def push_back(self, value: int) -> None:
self.deque.append(value)
def pop_front(self) -> int:
return self.deque.popleft() if self.deque else -1
#法2
import queue
class MaxQueue:
def __init__(self):
self.queue = queue.Queue()
self.deque = queue.deque()
def max_value(self) -> int:
return self.deque[0] if self.deque else -1
def push_back(self, value: int) -> None:
while self.deque and self.deque[-1] <value:
self.deque.pop()
self.deque.append(value)
self.queue.put(value)
def pop_front(self) -> int:
if not self.deque:
return -1
ans = self.queue.get()
if ans == self.deque[0]:
self.deque.popleft()
return ans
#法3
class MaxQueue:
def __init__(self):
self.queue = []
self.maxqueue = []
self.remove = []
def max_value(self) -> int:
while len(self.remove)>0 and len(self.maxqueue)>0 and self.remove[0] == self.maxqueue[0]:
heappop(self.remove)
heappop(self.maxqueue)
return -self.maxqueue[0] if len(self.maxqueue)>0 else -1
def push_back(self, value: int) -> None:
self.queue.append(value)
heappush(self.maxqueue,-value)
def pop_front(self) -> int:
if len(self.queue)>0:
heappush(self.remove,-self.queue[0])
return self.queue.pop(0)
return -1
剑指 Offer 60. n个骰子的点数
题意:
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
题解:
概率dp
设dp[i][j] 为使用i个骰子撒出点数j的概率
初始化:
dp[0][0] = 1
转移方程:
dp[i][j] = dp[i-1][j-k] * 1/6 其中k属于[1,6]表示此次撒出的点数
代码:
class Solution:
def dicesProbability(self, n: int) -> List[float]:
dp = [[0for col in range(70)]for row in range(20)]
dp[0][0]=1
for i in range(1,n+1):
for j in range(i,i*6+1):
for k in range(1,min(j+1,7)):
dp[i][j]+=dp[i-1][j-k]/6
return dp[n][n:n*6+1]
剑指 Offer 61. 扑克牌中的顺子
题意:
给出五个数,判断是否可构成连续递增序列,其中0可当任意数。
题解:
- 暴力判断。
- 去掉0后的最大值-最小值<5,且无重复 既满足条件
代码:
#法一
class Solution:
def isStraight(self, nums: List[int]) -> bool:
nums.sort()
cnt,lst = 0,-1
for i in range(5):
if nums[i] == 0:
cnt+=1
else :
if lst == -1:
lst =nums[i]
else :
if nums[i]==lst +1:
lst =nums[i]
elif nums[i]<lst+1:
return False
else:
while nums[i]>lst+1:
if cnt>0:
cnt,lst =cnt-1,lst+1
else :
return False
lst = nums[i]
return True
#法2
class Solution:
def isStraight(self, nums: List[int]) -> bool:
repeat = set()
ma, mi = 0, 14
for num in nums:
if num == 0: continue # 跳过大小王
ma = max(ma, num) # 最大牌
mi = min(mi, num) # 最小牌
if num in repeat: return False # 若有重复,提前返回 false
repeat.add(num) # 添加牌至 Set
return ma - mi < 5 # 最大牌 - 最小牌 < 5 则可构成顺子
剑指 Offer 62. 圆圈中最后剩下的数字
题意:
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
题解:
代码:
class Solution:
def lastRemaining(self, n: int, m: int) -> int:
f = 0
for i in range(2, n + 1):
f = (m + f) % i
return f
剑指 Offer 63. 股票的最大利润
题意:
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
题解:
低买高出。
遍历过程中维护此前出现过的最小值即可
代码:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices: return 0
mi,ans = prices[0],0
for i in prices[1:]:
ans = max(ans,i-mi)
mi = min(mi,i)
return ans
剑指 Offer 64. 求1+2+…+n
题意:
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
题解:
- 递归+判断条件利用 运算符(A&&B,A为False则B不会被执行)
- 暴力快速乘
以上是关于剑指offer59 - II 至 剑指offer 64 题解的主要内容,如果未能解决你的问题,请参考以下文章
剑指offer 65 至 剑指offer 68 - II 题解
剑指offer 65 至 剑指offer 68 - II 题解