【LeetCode: 剑指 Offer 60. n个骰子的点数 | 数学+ 暴力递归=>记忆化搜索=>动态规划】

news2024/10/5 20:28:05

在这里插入图片描述

🍎作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🍎座右铭:人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯🎯

在这里插入图片描述

目录

    • 题目链接
    • 题目描述
    • 求解思路&实现代码&运行结果
      • 暴力递归
        • 求解思路
        • 实现代码
        • 运行结果
      • 记忆化搜索
        • 求解思路
        • 实现代码
        • 运行结果
      • 动态规划
        • 求解思路
        • 实现代码
        • 运行结果
    • 共勉

题目链接

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

求解思路&实现代码&运行结果


暴力递归

求解思路

  1. 为了能够让同学们更好的理解这个过程,我特意将整个思考的过程以及作图的过程都绘制在下面这张图中,希望可以通过下面这张图更好的帮助你理解整个过程,大家可以结合这张图来理解整个题目的求解思路。

在这里插入图片描述

实现代码

class Solution {

    private int n;
    List<Double> list;
    public double[] dicesProbability(int n) {
        this.n=n;
        list=new ArrayList<>();
        int start=n,end=n*6;
        
        process(start,end,n);
        double[] ans=new double[list.size()];
        for(int i=0;i<list.size();i++){
            ans[i]=list.get(i);
        }
        return ans;
    }

    public void process(int start,int end,int cnt){
        for(int i=start;i<=end;i++){
            int count=dfs(i,cnt);
            list.add(1.0/Math.pow(6,n)*count);
        }
    }

    public int dfs(int target,int cnt){
        if(cnt==0) return target==0?1:0;
        int count=0;
        for(int i=1;i<=6;i++){
           count+=dfs(target-i,cnt-1); 
        }
        return count;
    }
}

运行结果

在这里插入图片描述


记忆化搜索

求解思路

  1. 根据我们递归的分析,在递归的过程中会产生重复的子过程,所以我们想到了加一个缓存表,也就是我们的记忆化搜索。

实现代码

class Solution {

    private int n;
    private List<Double> list;
    public double[] dicesProbability(int n) {
        this.n=n;
        list=new ArrayList<>();
        int start=n,end=n*6;
        process(start,end,n);
        double[] ans=new double[list.size()];
        for(int i=0;i<list.size();i++){
            ans[i]=list.get(i);
        }
        return ans;
    }

    public void process(int start,int end,int cnt){
        int[][] dp=new int[12*6][12];
        for(int i=0;i<dp.length;i++) Arrays.fill(dp[i],-1);
        for(int i=start;i<=end;i++){
            int count=dfs(i,cnt,dp);
            list.add(1.0/Math.pow(6,n)*count);
        }
    }

    public int dfs(int target,int cnt,int[][] dp){
        if(target<0) return 0;
        if(cnt==0) return dp[target][cnt]=target==0?1:0;
        if(dp[target][cnt]!=-1) return dp[target][cnt];
        int count=0;
        for(int i=1;i<=6;i++){
           count+=dfs(target-i,cnt-1,dp); 
        }
        return dp[target][cnt]=count;
    }
}

运行结果

在这里插入图片描述


动态规划

求解思路

  1. 接下来我们根据之前的递归思路以及记忆化缓存改写动态规划。

实现代码

class Solution {

    private int n;
    private List<Double> list;
    public double[] dicesProbability(int n) {
        this.n=n;
        list=new ArrayList<>();
        int start=n,end=n*6;
        process(start,end,n);
        double[] ans=new double[list.size()];
        for(int i=0;i<list.size();i++){
            ans[i]=list.get(i);
        }
        return ans;
    }

    public void process(int start,int end,int cnt){
        int[][] dp=new int[12*6][12];
        dp[0][0]=1;
        for(int target=1;target<=end;target++){
            for(int k=1;k<=cnt;k++){
                int count=0;
                for(int i=1;i<=6;i++){
                    if(target-i>=0) count+=dp[target-i][k-1]; 
                }
                dp[target][k]=count;
            }
            if(target>=start){
                list.add(1.0/Math.pow(6,n)*dp[target][cnt]);
            }   
        }
    }
}

运行结果

在这里插入图片描述


共勉

最后,我想送给大家一句一直激励我的座右铭,希望可以与大家共勉!
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/416530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git的操作使用三大块,常用的命令都在这里简单明了

码云网址&#xff1a;Gitee - 企业级 DevOps 研发效能平台 注册登录 创建仓库 仓库名称&#xff1a;必填&#xff0c;每个仓库都需要有一个名称&#xff0c;同一个码云账号下的仓库名称不能重复 路径&#xff1a;访问远程仓库时会使用到&#xff0c;一般无需手动指定&#xf…

C. Pinkie Pie Eats Patty-cakes(二分)

Problem - C - Codeforces 小粉饼买了一袋不同馅料的馅饼饼!但并不是所有的馅饼饼在馅料上都各不相同。换句话说&#xff0c;这个袋子里有一些馅料相同的馅饼。小粉派一个接一个地吃蛋糕。她喜欢玩&#xff0c;所以她决定不只是吃馅饼蛋糕&#xff0c;而是尽量不经常吃同样馅料…

Android 性能优化——ANR监控与解决

作者&#xff1a;Drummor 1 哪来的ANR ANR(Application Not responding):如果 Android 应用的界面线程处于阻塞状态的时间过长&#xff0c;会触发“应用无响应”(ANR) 错误。如果应用位于前台&#xff0c;系统会向用户显示一个对话框。ANR 对话框会为用户提供强制退出应用的选项…

Mybatis03学习笔记

目录 使用注解开发 设置事务自动提交 mybatis运行原理 注解CRUD lombok使用&#xff08;偷懒神器&#xff0c;大神都不建议使用&#xff09; 复杂查询环境&#xff08;多对一&#xff09; 复杂查询环境&#xff08;一对多&#xff09; 动态sql环境搭建 动态sql常用标签…

Unity Game FrameWork—模块使用—对象池分析

官方说明&#xff1a;提供对象缓存池的功能&#xff0c;避免频繁地创建和销毁各种游戏对象&#xff0c;提高游戏性能。除了 Game Framework 自身使用了对象池&#xff0c;用户还可以很方便地创建和管理自己的对象池。 下图是Demo中用到的对象池&#xff0c;所有的实体以及UI都使…

SpringBoot集成ChatGPT实现AI聊天

前言 ChatGPT已经组件放开了&#xff0c;现在都可以基于它写插件了。但是说实话我还真没想到可以用它干嘛&#xff0c;也许可以用它结合文字语音开发一个老人小孩需要的智能的说话陪伴啥的。 今天我就先分享下SpringBoot结合ChatGPT&#xff0c;先看看对话效果。 一、依…

清明-前端

明天面快手前端&#xff0c;正好借这个机会&#xff0c;做做毕设吧。顺便整理一下前端的面试内容。 何良蓉说&#xff0c;他觉得学的时候开心&#xff0c;玩的时候也开心。我觉得不开心。可能他掌握生活的秘密了吧。 如果他没对我撒谎的话。 看了眼别人的面经&#xff0c;就知…

一键禁用系统防火墙

你也可以通过批处理命令来实现 桌面空白地方右键选择新建记事本将下面代码复制到记事本里&#xff0c;然后保存为.bat类型的文件&#xff1b;保存完成运行即可。 Echo off Echo -------------------------------------------------------------------------- Echo 禁用系统防火…

【CSS】定位 ② ( 静态定位 | 相对定位 )

文章目录一、静态定位二、相对定位1、标准流下的盒子模型代码示例2、相对定位下的盒子模型代码示例一、静态定位 CSS 中的 静态定位 是 默认的定位方式 , 就是无定位 , 设置该定位方式 , 定位盒子不生效 ; 为盒子模型 设置 静态定位 模式 , 该 盒子模型 就会按照标准流的方式 …

【面试】spring中怎么解决循环依赖问题?

文章目录前言1、什么是循环依赖&#xff1f;2、Spring怎么解决循环依赖3、如何解决&#xff1f;4、怎么样的循环依赖无法处理?5、总结:前言 思考: 什么是循环依赖&#xff1f;Spring怎么解决循环依赖Spring对于循环依赖无法解决的场景 1、什么是循环依赖&#xff1f; 循环…

Run Loops

Run Loops 运行循环是与线程相关的基本基础结构的一部分。运行循环是事件处理循环&#xff0c;用于安排工作并协调传入事件的接收。运行循环的目的是在有工作要做时让线程保持忙碌&#xff0c;在没有工作要做时让线程休眠。 运行循环管理不是完全自动的。您仍然必须设计线程代…

【Java Web】012 -- SpringBootWeb综合案例(登录功能、登录校验、异常处理)

目录 一、登录功能 1、基础登录功能 ①、SQL语句 ②、接口参数 ③、实现思路 ④、实现步骤 2、联调Bug&#xff08;没有Cookie或Session&#xff09; 二、登录校验 1、登录校验的实现思路 2、会话技术 ①、会话与会话跟踪 ②、会话跟踪方案对比 Cookie Session …

C# 多线程编程

1 线程与进程 进程&#xff1a;进程可以理解为一块包含了某些些资源的内存区域&#xff0c;操作系统通过进程这一方式把他的工作划分为不同的单元。一个应用程序可以对应于多个进程。 线程&#xff1a;线程是进程中的独立执行单元&#xff0c; 对于操作系统而言&#xff0c;他…

【学习笔记】unity脚本学习(四)【inputManager、键盘输入、鼠标输入、Raycast】

目录输入inputManagerHorizontal虚拟轴的各个属性含义&#xff08;摘选自ChatGpt&#xff0c;部分回答不准确&#xff09;键值的含义键名称命名约定&#xff1a;键盘输入静态函数GetKeyGetButtonKeyCodeGetButton/Down/upGetAxisGetAxisRaw 返回由 axisName 标识的虚拟轴的值&a…

【Gradle-2】一文搞懂Gradle配置

1、前言 “Gradle的配置太多了&#xff0c;经常版本更新还有变化&#xff0c;而且它还能扩展&#xff0c;记是记不住了&#xff0c;只能用到再搜了&#xff0c;哎&#xff0c;难顶” 真的难顶&#xff0c;但是我想挑战一下… 本文介绍的重点&#xff1a; Gradle配置简介Grad…

slam与导航开发

Gmapping是一种基于激光雷达数据的地图构建算法&#xff0c;可以用于建立机器人的环境地图。 Gmapping算法是基于粒子滤波器&#xff08;Particle Filter&#xff09;的SLAM算法&#xff0c;它通过将机器人在环境中的位姿和地图中的特征进行联合估计&#xff0c;实现了机器人在…

个人使用mac OS和win OS的差异

苹果 macOS 操作系统和 Windows 操作系统在很多方面有所不同&#xff0c;主要体现在以下几个方面&#xff1a; 用户界面&#xff1a;macOS 和 Windows 的用户界面风格不同。macOS 推崇简洁、优雅的设计&#xff0c;注重操作体验&#xff1b;Windows 软件更为丰富&#xff0c;但…

Doris(1):Doris介绍

1 Doris简介 Apache Doris是一个现代化的基于MPP&#xff08;大规模并行处理&#xff09;技术的分析型数据库产品。简单来说&#xff0c;MPP是将任务并行的分散到多个服务器和节点上&#xff0c;在每个节点上计算完成后&#xff0c;将各自部分的结果汇总在一起得到最终的结果(…

最小生成树和最短路径及其他

还是学过的&#xff0c;主要用于复习q v q 一、最小生成树 最小生成树的定义 用于无向图中&#xff0c;无向图指的是没有带方向路径的图&#xff0c;给定n个点&#xff0c;m条边&#xff0c;如果将这些点依次相连&#xff0c;求出连接这些点的最小数值 应用场景 根据这个算…

9 个JSON.stringify的秘密大多数开发人员却不知道

作为前端开发工程师&#xff0c;你一定用过JSON.stringify&#xff0c;但你知道它的全部秘密吗&#xff1f; 很久以前&#xff0c;我因此在工作中犯下了无法挽回的错误。如果我早点知道&#xff0c;就不会发生这样的悲剧。 理解 JSON.stringify 基本上&#xff0c;JSON.stri…