[剑指Offer]60~64

[剑指Offer]60~64

学习使用工具

剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf

LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/

剑指 Offer 60. n个骰子的点数

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。

你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

示例 1:

输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]

示例 2:

输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]

限制:

1 <= n <= 11

解法:

动态规划。设输入 n 个骰子的解为 \(f(n)​\),其中点数和为 x 的概率为 \(f(n,x)​\)。有递推公式:\(f(n,x)=\sum^6_{i=1}f(n-1,x-i)*{1\over6}​\)

def dicesProbability(self, n: int) -> List[float]:
        dp = [1 / 6] * 6
        for i in range(2, n + 1):
            tmp = [0] * (5 * i + 1)
            for j in range(len(dp)):
                for k in range(6):
                    tmp[j + k] += dp[j] / 6
            dp = tmp
        return dp

剑指 Offer 62. 圆圈中最后剩下的数字

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例 1:

输入: n = 5, m = 3
输出: 3

示例 2:

输入: n = 10, m = 17
输出: 2

限制:

  • 1 <= n <= 10^5
  • 1 <= m <= 10^6

解法:

约瑟夫环问题。递推公式:\(f ( N , M ) = ( f ( N − 1 , M ) + M ) % N f(N,M)=(f(N-1,M)+M)\%N\)

\(f ( N , M )\) 表示,N个人报数,每报到M时那个人出局,最终胜利者的编号

\(f ( N − 1 , M )\) 表示,N-1个人报数,每报到M时那个人出局,最终胜利者的编号

def lastRemaining(self, n: int, m: int) -> int:
        ans = 0
        for i in range(2, n + 1):
            ans = (ans + m) % i

        return ans

剑指 Offer 63. 股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

限制:

0 <= 数组长度 <= 10^5

解法:

维护一个当前最小值l,一个当前最大值r,以及最大利润值profit。初始,l和r都等于数组第一个元素,profit为0,遍历数组:

  • 如果当前数组元素小于l,则令l和r都等于当前元素;
  • 如果当前数组元素大于r,则令r等于当前元素,更新profit=max(profit, r-l)
def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0

        l = prices[0]
        r = prices[0]
        profit = r - l

        for i in range(len(prices)):
            if prices[i] < l:
                l = prices[i]
                r = prices[i]
            elif prices[i] > r:
                r = prices[i]
                profit = max(profit, r - l)
                
        return profit

剑指 Offer 64. 求1+2+…+n

1+2+...+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

示例 1:

输入: n = 3
输出: 6

示例 2:

输入: n = 9
输出: 45

限制:

  • 1 <= n <= 10000

解法:

?什么意思

def sumNums(self, n: int) -> int:
        return sum(range(1, n + 1))

原来是要递归代替循环,逻辑运算符代替if。

常见的逻辑运算符有三种,而其有重要的短路效应,如下所示:

本题需要实现 “当 n=1 时终止递归” 的需求,可通过短路效应实现。

n > 1 && sumNums(n - 1) // 当 n = 1 时 n > 1 不成立 ,此时 “短路” ,终止后续递归

class Solution:
    def __init__(self):
        self.res = 0
    def sumNums(self, n: int) -> int:
        n > 1 and self.sumNums(n - 1)
        self.res += n
        return self.res
posted @ 2023-03-06 14:51  无机呱子  阅读(17)  评论(0编辑  收藏  举报