这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战
n个骰子的点数
剑指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个骰子,如果采用暴力法,那么时间复杂度将会达到O(),显然不切实际。
动态规划
由于后面的概率或者点数和与前面骰子的概率和点数和有关系,我们可以使用动态规划的方式解决这道题。
步骤如下:
-
设置dp为每轮掷骰子的点数和的概率,初始为点数和为1-6的概率均为。
-
根据掷骰子的次数,来进行循环
- 设置tmp为该轮掷骰子的点数和的概率,初始为全0。若掷5颗骰子,5个全1的情况下,能得到最小的点数和为5,同理,不难得出最小点数和为6n-n+1 = 5n+1。
- 根据上一次的dp结果,与每轮掷骰子的tmp[i]一起交替前进,因为新增骰子的点数只可能是1至6,因此每一次tmp前进时都要加上「上一次的结果/6」。
- 算完tmp后将tmp赋值给dp,以便下一次可以使用。
-
遍历结束,返回dp。
/**
* @param {number} n
* @return {number[]}
*/
var dicesProbability = function (n) {
let dp = new Array(6).fill(1/6);
for (let i = 2; i <= n; i++) {
let tmp = new Array(5 * i + 1).fill(0);
for (let j = 0; j < dp.length; j++) {
for (let k = 0; k < 6; k++) {
tmp[j + k] += dp[j] / 6;
}
}
dp = tmp;
}
return dp;
};
- 时间复杂度:O(N^2)
- 空间复杂度:O(N)
扑克牌的顺子
剑指Offer 61. 扑克牌中的顺子
难度:简单
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王都为0,可以看成任意数字。A不能视为14。
示例1:
输入: [1,2,3,4,5]
输出: True
示例2:
输入: [0,0,1,2,5]
输出: True
限制:数组长度为5,数组的数取值为[0,13]。
题解
一开始看到示例2很疑惑,为啥[0,0,1,2,5]
是一个顺子,其实就是说0是一张万能牌,用0可以充当任何一张牌,就可以将其看成[1,2,3,4,5]
啦。
判断5张牌是顺子的条件如下:
- 除了大小王外,其他所有牌无重复
- 5张牌中需满足「最大的牌 - 最小的牌(大小王除外) < 5」
法一 集合 + 遍历
- 使用Set去重
- 遍历的时候获取最大牌max和最小牌min。
/**
* @param {number[]} nums
* @return {boolean}
*/
var isStraight = function (nums) {
const set = new Set();
let max = 0,
min = 14;
for (let num of nums) {
if (num === 0) continue;
max = Math.max(max, num);
min = Math.min(min, num);
if (set.has(num)) return false;
set.add(num);
}
return max - min < 5;
};
- 时间复杂度:O(N),本题中N为5
- 空间复杂度:O(N)
法二 排序 + 遍历
- 先对数组排序
- 判断nums[i]是否与nums[i+1]相等(判断重复),相等则直接返回false
- 排序后,末尾元素nums[4]为最大牌,元素nums[joker]为最小牌,其中joker为大小王的数量
var isStraight = function (nums) {
let joker = 0; // 用于判断大小王的数量,从而作为下标
nums.sort((a, b) => a - b); // 记得加上sort()内的函数
// for循环只需要判断前4位即可
for (let i = 0; i < 4; i++) {
if (nums[i] === 0) joker++;
else if (nums[i] === nums[i + 1]) return false;
}
return nums[4] - nums[joker] < 5;
};
- 时间复杂度:O(NlogN),sort使用的是快排需要O(NlogN)
- 空间复杂度:O(1)
坚持每日一练!前端小萌新一枚,希望能点个赞
哇~