leetcode《图解数据结构》刷题日志【第五周】(2022/11/21-2022/11/28)

news2025/1/19 7:11:00

leetcode《图解数据结构》刷题日志【第五周】

  • 1. 剑指 Offer 60. n 个骰子的点数
    • 1.1 题目
    • 1.2 解题思路
    • 1.3 数据类型功能函数总结
    • 1.4 java代码
    • 1.5 踩坑小记
    • 1.6 进阶做法
  • 2. 剑指 Offer 63. 股票的最大利润
    • 2.1 题目
    • 2.2 解题思路
    • 2.3 数据类型功能函数总结
    • 2.4 java代码
  • 3. 剑指 Offer 12. 矩阵中的路径
    • 3.1 题目
    • 3.2 解题思路
    • 3.3 数据类型功能函数总结
    • 3.4 java代码
  • 4. 剑指 Offer 13. 机器人的运动范围
    • 4.1 题目
    • 4.2 解题思路
    • 4.3 数据类型功能函数总结
    • 4.4 java代码
    • 4.5 另解

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

1.1 题目

把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.2 解题思路

n个骰子想掷出点数i,需要第n个骰子掷出点数x,前n-1个骰子一共掷出点数i-x。因此n个骰子出现点i的概率记作dp[n][i],则dp[n][i+1]=dp[n-1][i-x] * dp[1][x]
dp[1][x]=1/6。所以可直接将状态转移公式写为dp[n][i+1]=dp[n-1][i-x]/6.0
因此,最直接的思路可以定义一个二维数组,根据上一行的结果确定该行的概率结果。

1.3 数据类型功能函数总结

//二维数组相关操作
double[][] name=new double[line_size][row_size];//定义。

1.4 java代码

class Solution {
    public double[] dicesProbability(int n) {
        double[][] dp=new double[n+1][6*n+1];//行--n,列--n~6*n,保证下标和骰子编号对应
        int i,j;
        for(i=1;i<=6;i++){
            dp[1][i]=1.0/6.0;
        }
        for(i=2;i<=n;i++){//处理每一行
            for(j=1;j<i;j++){
                dp[i][j]=0;
            }
            for(j=i;j<=n*6;j++){//处理每一列 2,3,4,5,6,7,8,9,10,11,12
                for(int k=1;k<=6;k++){//
                    if(j-k>=i-1){
                        dp[i][j]+=dp[i-1][j-k]/6.0; //dp[1][1] dp[1][2] dp[1][3]
                    }
                }
            }
        }
        //获取最后一行的结果。
        double[] re=new double[5*n+1];
        for(i=n,j=0;i<=6*n;i++,j++){
            re[j]=dp[n][i];
        }
        return re;
    }
}

1.5 踩坑小记

1、计算出来的概率在最后一位总是比结果值大1;
原因在于我将1个骰子投出的结果按照输出样例的格式,写成1.6667(小数形式)而不是1/6的分式。
导致后面的运算过程中计算的是1.6667*1.6667而不是1/6*1/6的结果。
虽然刚开始这点误差没有什么,但是随着骰子数目增多,这样的误差会影响结果的数值。

修改的方式也很简单,将小数形式都改成分数形式即可。

1.6 进阶做法

根据官方题解的思路,dp[n][]的求解实际上只依赖于dp[n-1][]的6个元素值,因此,我们可以只定义两个一维数组,用类似于“滚动数组”的方式来写。

class Solution {
    public double[] dicesProbability(int n) {
        double[] dp=new double[6];//
        int i,j;
        //处理初始值
        for(i=0;i<6;i++){
            dp[i]=1.0/6.0;
        }
        for(i=2;i<=n;i++){//骰子数不断增加,i表示当前骰子数量
            double[] dp_new= new double[5*i+1];//新的结果数量为6*i-(i-1)=5*i+1;
            for(j=0;j<dp.length;j++){
                for(int k=0;k<6;k++){//每个元素项等于若干项之和
                //这两个for循环对应了dp_new中所有的结果情况,妙啊
                    dp_new[j+k]+=dp[j]/6.0;
                }
            }
            dp=dp_new;
        }
        return dp;
    }
}

不过我发现,使用1.4的一般解法,反而空间利用更少,而下面的进阶做法,空间利用更大了。
如图是1.4 一般做法的提交结果
在这里插入图片描述

如图是1.6 进阶做法的提交结果
在这里插入图片描述

总之就是很迷,不知道有没有大佬能解释这个现象。

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

2.1 题目

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

示例 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

2.2 解题思路

最简单的思路:买卖一次股票,查找最小值买入,在最小值之后的数据中查找最大值_但是存在次优解的情况,所以这种思路pass.

使用动态规划,则假设dp[i]表示第i天为止的最低卖出价格,最大利润为price[i]-dp[i]
状态转移方程设计如下:

  • 如果price[i]<dp[i],表示买入价格可更低,dp[i]=price[i];表示更新买入
  • price[i]>dp[i],表示可以卖出,则dp[i]=dp[i-1],考虑卖出之后的利润是不是最大的。

为了降低空间复杂度,本题中dp[i]只和dp[i-1]有关,所以只需要设置一个整型数字即可。profit变量总是在可卖出的时候记录当前最大的卖出利润,也可以理解为一个动态规划问题。

这种思路和官方的解题思路异曲同工,官方解法里面cost是本思路中的dp[i],官方题解中的dp[i]是本思路中的profit.

2.3 数据类型功能函数总结

//none

2.4 java代码


class Solution {
    public int maxProfit(int[] prices) {
        int profit=0;
        if(prices.length==0){return 0;}
        int dp=prices[0];
        for(int i=1;i<prices.length;i++){
            if(prices[i]<dp){//更新买入
                dp=prices[i];
            }
            else{//考虑卖出
                if(prices[i]-dp>profit){
                    profit=prices[i]-dp;
                }
            }
        }
        return profit;  
    }
}

3. 剑指 Offer 12. 矩阵中的路径

3.1 题目

给定一个m x n 二维字符网格board 和一个字符串单词word 。如果word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
    输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
    输出:true
示例 2:
    输入:board = [["a","b"],["c","d"]], word = "abcd"
    输出:false

提示:
    m == board.length
    n = board[i].length
    1 <= m, n <= 6
    1 <= word.length <= 15
    board 和 word 仅由大小写英文字母组成

3.2 解题思路

个人思路是从起点开始,每次往四个方向查找,如果都没有合适的则默认一个特定的顺序进行四周的搜索,找到第一个字符之后,继续查找,为了回溯设置一个查找标记的矩阵,和board对应。
结合官方题解,主要解决了我在这个思路中的三个疑问:

  • 如何查找到第一个元素:根据官方题解和代码参考,地毯式遍历行列中的元素,如果以某个元素为起点进行搜索得到了最终的结果,则说明矩阵中有字符串,否则则在所有元素遍历完成之后说明矩阵中没有该字符。
  • 如何进行遍历和方向搜索:官方题解中给出了DFS深度优先搜索算法,并且使用递归的方式来实现。终止条件设置为越界或者字符不匹配的时候或者查找结束之后,而递归部分分别查找上下左右四个方位,只要有一个方向能走得下去即可。
  • 如何进行矩阵元素标记和回溯:为了节省空间,可考虑直接修改矩阵内元素而不是另外开辟一块空间;遍历过的元素则修改为"\0"字符,如果遍历搜索失败,需要回溯,则使用word字符串的当前搜索位置还原被标记的元素。
    DFS算法的递归实现是核心重点。

3.3 数据类型功能函数总结

//二维数组相关操作
int line=array_name.length;//获取行数
int row=array_name[0].length;//获取列数
//字符串相关操作
String.length();//获取字符串长度
String.charAt(index);//获取某个下标的对应字符。

3.4 java代码


class Solution {
    public boolean exist(char[][] board, String word) {
        int i=0,j=0,index=0;;
        int line=board.length;
        int row=board[0].length;
        for(i=0;i<line;i++){
            for(j=0;j<row;j++){
                if(dfs(board,word,i,j,0)==true){
                    return true;
                }
            }
        }
        return false;
    }
    boolean dfs(char[][] board,String word,int i,int j,int k){//递归函数
        if(i >=board.length || j >= board[0].length || j<0||i<0||board[i][j]!=word.charAt(k)){
            return false;
        }
        if(k==word.length()-1){
            return true;
        }
        board[i][j]='\0';
        boolean re=dfs(board,word,i+1,j,k+1)||dfs(board,word,i-1,j,k+1)||dfs(board,word,i,j+1,k+1)||dfs(board,word,i,j-1,k+1);
        board[i][j]=word.charAt(k);
        return re;
    }
}

4. 剑指 Offer 13. 机器人的运动范围

4.1 题目

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:
    输入:m = 2, n = 3, k = 1
    输出:3

示例 2:
    输入:m = 3, n = 1, k = 0
    输出:1

提示:
    1 <= n,m <= 100
    0 <= k?<= 20

4.2 解题思路

和矩阵中的路径类似,需要考虑的是矩阵中的搜索问题,因此还是使用dfs搜索进行矩阵遍历。

终止条件:达到边界或者行坐标和列坐标位数大于k,n和m最大也是二位数。
递归部分:左、右、上、下进行搜索,每次搜索到一个格子,进行格子统计。

后来经过代码测试和题解的提示,首先需要设置访问矩阵记录访问过的元素值,从而避免同一个单元格多次统计;还有就是由于解的区域是三角形,可以仅考虑搜索右下方向来进行矩阵搜索。【很有意思的点,如果直接四个方向访问的话,会出现栈溢出的情况】

4.3 数据类型功能函数总结

//数组相关操作
int[] array_name=new int[]{初始的元素值};//数组定义方式1
int[] array_name=new int[len];//数组定义方式2
//矩阵相关操作
int[][] array_name=new int[line_len][row_len];//矩阵定义
//队列相关操作
LinkedList<> queue_name=new LinkedList<>();//队列结构用linkedlist实现
queue_name.add();//添加元素
queue_name.poll();//弹出元素
queue_name.size();//获得队列大小

4.4 java代码

class Solution {
    int m,n,k;
    int[][] visited;
    public int movingCount(int m, int n, int k) {
        int re=1;
        visited=new int[m][n];
        re=dfs(m,n,k,0,0);
        return re;
    }
    public int dfs(int m, int n, int k,int i,int j) {
        if(i>=m||j>=n||i<0||j<0||i%10+i/10+j%10+j/10>k||visited[i][j]==1){
            return 0;
        }
        else{
            visited[i][j]=1;
            int re=1;
            re+=dfs(m,n,k,i+1,j)+dfs(m,n,k,i,j+1);
            return re;
        }
    }
}

4.5 另解

搜索回溯类的问题另外一种解法思路是广度优先遍历,深度优先遍历DFS需要借助栈结构,可递归实现,对应的,广度优先遍历需要借助队列结构。

class Solution {
    int m,n,k;
    int[][] visited;
    LinkedList<int[]> queue=new LinkedList<int[]>();//队列结构
    public int movingCount(int m, int n, int k) {
        int re=0;
        visited=new int[m][n];
        //广度优先遍历
        queue.add(new int[]{0,0});//初始的i,j
        while(queue.size()!=0){
            int[] temp=queue.poll();
            int i=temp[0],j=temp[1];
            if(i<m && j<n && i>=0 && j>=0 && (i/10+i%10+j/10+j%10)<=k && visited[i][j]!=1){
                re++;//统计到达的格子
                queue.add(new int[]{i+1,j});
                queue.add(new int[]{i,j+1});
                visited[i][j]=1;
            }
        }
        return re;
    }
}

又是只完成一半任务的一周(衰

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

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

相关文章

SpringBoot SpringBoot 原理篇 1 自动配置 1.16 自动配置原理【2】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇1 自动配置1.16 自动配置原理【2】1.16.1 看源码了1.16.2 Import({AutoConfig…

archlinux 安装matlab

最近在学matlab使用的是windows版本的&#xff0c;比起windows我更喜欢在linux中写代码。于是乎就想在Linux中安装一下。 主要过程参考此篇文章&#xff1a; 《【首发】 ubuntu20.04安装matlab2021b/matlab2020b》 https://blog.csdn.net/hanjuefu5827/article/details/1151677…

【Hack The Box】Linux练习-- Forge

HTB 学习笔记 【Hack The Box】Linux练习-- Forge &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月27日&#x1f334; &#x1f36…

队列(C语言实现)

文章目录&#xff1a;1.队列的概念2.队列的结构3.接口实现3.1初始化队列3.2判断队列是否为空3.3入队3.4出队3.5查看队头元素3.6查看队尾元素3.7统计队列数据个数3.8销毁队列1.队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特…

jQuery插件【validate】国际化校验插件

jQuery插件系列 相信大家在网站上都遇到过这种注册的情况吧&#xff0c;有的时候我们什么也不输入点登录或者注册或者鼠标失去焦点的时候&#xff0c;就会自动提示xxx为空&#xff0c;密码不正确&#xff0c;请输入xxx等一系列的提示信息。 那么这是怎么实现的呢&#xff0c;其…

【LeetCode】No.101. Symmetric Tree -- Java Version

题目链接&#xff1a;https://leetcode.com/problems/symmetric-tree/ 1. 题目介绍&#xff08;Symmetric Tree&#xff09; Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center). 【Translate】&#xff1a; 给定…

QT实战项目1——无边框窗口拖拽和阴影

课时2 开发环境,无边框窗口拖拽和阴影_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV14t411b7EL?p2&vd_source0471cde1c644648fafd07b54e303c905 目录 一、设置无边框 和 鼠标可以拖动窗口 1.1 设置无边框 1.2 鼠标拖动 1.3 展示阴影 一、设置无边框 和 鼠标可…

设计模式-组合模式

组合模式一、学校院系展示需求二、传统方案解决学校院系展示三、组合模式基本介绍四、组合模式原理类图五、组合模式解决的问题六、使用组合模式解决院校展示问题6.1、类图6.2、代码一、学校院系展示需求 编写程序展示一个学校院系结构&#xff1a;需求是这样&#xff0c;要在…

SQL练习题

新建数据表 首先建立测试数据库的表&#xff0c;新建数据库的sql语句如下&#xff0c;大家可以粘贴成一个sql文件&#xff0c;然后新建所有的表并插入所有的数据&#xff1a; 新建数据库sql文件&#xff1a; DROP TABLE IF EXISTS EMP; DROP TABLE IF EXISTS DEPT; DROP TAB…

Unity UI锚点和位置关系

一、Anchors锚点 Anchors的设置会直接改变RectTransform中它的位置信息&#xff1b;Anchors设置中的X 改变会影响&#xff08;PosX和Width&#xff09;或&#xff08;left和right&#xff09; 1、Anchors改变位置信息 下图中X锚点的Min和Max值相同时&#xff0c;上面的一栏中…

Java调用命令行并返回打印的内容

博主在最近的工作中&#xff0c;收到了这样一个需求。 调用别人以前完成开发的 jar 包或 python 程序&#xff0c;并将原程序在命令行中输出的内容封装为 JSON 对象后通过 RESTFul 接口返回。 面对以上的需求&#xff0c;博主给出了以下解决方案。话不多说&#xff0c;上代码。…

Mathematica for Linux v13.1.0 科学计算软件多语言版

Wolfram Mathematica for Linux 中文正式版是一款强大的数学计算科学计算软件&#xff0c;MathWorks MATLAB 和 Wolfram Mathematica 、Maplesoft Maple 并称为三大数学软件&#xff0c;Wolfram Mathematica 中文正式版主要用于符号计算软件&#xff0c;也称为计算机代数系统&a…

MySQL如何恢复不小心误删的数据记录(binlog)

前言 题主于今天&#xff08;2022年11月27日&#xff09; 在线上环境误操作删除了记录&#xff0c;且没有备份数据&#xff0c;通宵排查事故原因&#xff0c;终于没有酿成生产事故。谨以此文记录。 参考资料 https://blog.csdn.net/qq_23543983/article/details/127298578 …

单源最短路径问题(Java)

单源最短路径问题&#xff08;Java&#xff09; 文章目录单源最短路径问题&#xff08;Java&#xff09;1、问题描述2、算法思路3、代码实现4、算法正确性和计算复杂性4.1 贪心选择性质4.2 最优子结构性质4.3 计算复杂性5、参考资料1、问题描述 给定带权有向图G(V,E),其中每条…

分布式电源接入对配电网的影响matlab程序(IEEE9节点系统算例)

分布式电源接入对配电网的影响matlab程序&#xff08;IEEE9节点系统算例&#xff09; 摘 要&#xff1a;分布式电源的接入使得配电系统从放射状无源网络变为分布有中小型电源的有源网络。带来了使单向流动的电流方向具有了不确定性等等问题&#xff0c;使得配电系统的控制和管…

Android反编译apk

文章目录安装Android Studio1. 解压apk文件方法一&#xff1a;使用apktool反编译&#xff08;得到的是.smali文件和可直接读的资源文件&#xff0c;如果要得到.dex文件&#xff0c;还要看方法二&#xff09;方法二&#xff1a;使用解压工具解压&#xff08;得到的是.dex文件和二…

SpringBoot项目集成Dubbo

1.环境搭建 为整合Dubbo之前&#xff0c;我们所写的项目都是单一应用架构&#xff0c;只需要一个应用&#xff0c;将所有功能都部署在一起&#xff0c;在应用内部是控制层调用业务层&#xff0c;业务层调用数据持久层&#xff1b;如今&#xff0c;整合Dubbo后&#xff0c;我们…

独立产品灵感周刊 DecoHack #039 - 制作自己的音乐墙

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。自荐产品 1. planet-tab - 由独立开发者 ha…

【云原生】Docker的私有仓库部署——Harbor

内容预知 1.Docker原生私有仓库—— Registry 1.1 Registry的简单了解 1.2 Registry的部署过程 步骤一&#xff1a;拉取相关的镜像 步骤二&#xff1a;进行 Registry的相关yml文件配置&#xff08;docker-compose&#xff09; 步骤三&#xff1a;镜像的推送 2. Registry的…

SpringBoot SpringBoot 原理篇 2 自定义starter 2.6 拦截器开发

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇2 自定义starter2.6 拦截器开发2.6.1 拦截器开发2.6.2 小结2 自定义starter …