[剑指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