剑指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可当任意数。

题解:

  1. 暴力判断。
  2. 去掉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)。

题解:

  1. 递归+判断条件利用 运算符(A&&B,A为False则B不会被执行)
  2. 暴力快速乘

以上是关于剑指offer59 - II 至 剑指offer 64 题解的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer(59)-II

剑指offer 65 至 剑指offer 68 - II 题解

剑指offer 65 至 剑指offer 68 - II 题解

剑指offer 65 至 剑指offer 68 - II 题解

剑指 Offer 53 - I 至 55-II题解

剑指 Offer 53 - I 至 55-II题解