【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】

在这里插入图片描述

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

在这里插入图片描述

目录

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

题目链接

375. 猜数字大小 II

题目描述

我们正在玩一个猜数游戏,游戏规则如下:

我从 1 到 n 之间选择一个数字。
你来猜我选了哪个数字。
如果你猜到正确的数字,就会赢得游戏 。
如果你猜错了,那么我会告诉你,我选的数字比你的更大或者更小 ,并且你需要继续猜数。
每当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。如果你花光了钱,就会输掉游戏 。
给你一个特定的数字 n ,返回能够确保你获胜的最小现金数,不管我选择那个数字 。

示例 1:
【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】_第1张图片

输入:n = 10
输出:16
解释:制胜策略如下:

  • 数字范围是 [1,10] 。你先猜测数字为 7 。
    • 如果这是我选中的数字,你的总费用为 $0 。否则,你需要支付 $7 。
    • 如果我的数字更大,则下一步需要猜测的数字范围是 [8,10] 。你可以猜测数字为 9 。
      • 如果这是我选中的数字,你的总费用为 $7 。否则,你需要支付 $9 。
      • 如果我的数字更大,那么这个数字一定是 10 。你猜测数字为 10 并赢得游戏,总费用为 $7 + $9 = $16 。
      • 如果我的数字更小,那么这个数字一定是 8 。你猜测数字为 8 并赢得游戏,总费用为 $7 + $9 = $16 。
    • 如果我的数字更小,则下一步需要猜测的数字范围是 [1,6] 。你可以猜测数字为 3 。
      • 如果这是我选中的数字,你的总费用为 $7 。否则,你需要支付 $3 。
      • 如果我的数字更大,则下一步需要猜测的数字范围是 [4,6] 。你可以猜测数字为 5 。
        • 如果这是我选中的数字,你的总费用为 $7 + $3 = $10 。否则,你需要支付 $5 。
        • 如果我的数字更大,那么这个数字一定是 6 。你猜测数字为 6 并赢得游戏,总费用为 $7 + $3 + $5 = $15 。
        • 如果我的数字更小,那么这个数字一定是 4 。你猜测数字为 4 并赢得游戏,总费用为 $7 + $3 + $5 = $15 。
      • 如果我的数字更小,则下一步需要猜测的数字范围是 [1,2] 。你可以猜测数字为 1 。
        • 如果这是我选中的数字,你的总费用为 $7 + $3 = $10 。否则,你需要支付 $1 。
        • 如果我的数字更大,那么这个数字一定是 2 。你猜测数字为 2 并赢得游戏,总费用为 $7 + $3 + $1 = $11 。
          在最糟糕的情况下,你需要支付 $16 。因此,你只需要 $16 就可以确保自己赢得游戏。

示例 2:
输入:n = 1
输出:0
解释:只有一个可能的数字,所以你可以直接猜 1 并赢得游戏,无需支付任何费用。

示例 3:
输入:n = 2
输出:1
解释:有两个可能的数字 1 和 2 。

  • 你可以先猜 1 。
    • 如果这是我选中的数字,你的总费用为 $0 。否则,你需要支付 $1 。
    • 如果我的数字更大,那么这个数字一定是 2 。你猜测数字为 2 并赢得游戏,总费用为 $1 。
      最糟糕的情况下,你需要支付 $1 。

提示:
1 <= n <= 200

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

暴力递归

求解思路

  1. 为了能够让同学们更好的理解这个过程,我特意将整个思考的过程以及作图的过程都绘制在下面这张图中,希望可以通过下面这张图更好的帮助你理解整个过程,大家可以结合这张图来理解整个题目的求解思路。
    【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】_第2张图片

实现代码

注意,代码的实现方式可以有很多,大家根据自己的习惯来就好

class Solution {
    public int getMoneyAmount(int n) {
        return process(1,n);
    }

    public int process(int left,int right){
        if(left>=right) return 0;
        int min=Integer.MAX_VALUE;
        for(int x=left;x<=right;x++){
            int pay=Math.max(process(left,x-1),process(x+1,right))+x;
            min=Math.min(min,pay);
        }
        return min;
    }
}

运行结果

大家不要看到时间超限就害怕,相反,看到这个我们更应该放心,这是我们期待的结果。

【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】_第3张图片

记忆化搜索

求解思路

  1. 核心思路就是我们上面的求解过程,如果没有理解可以继续看上面的图解过程。
  2. 在原来的基础上加缓存表,将结果进行记录,避免重复计算。

实现代码

class Solution {
    public int getMoneyAmount(int n) {
        int[][] dp=new int[n+5][n+5];
        for(int i=0;i<=n;i++) Arrays.fill(dp[i],-1);
        return process(1,n,dp);
    }

    public int process(int left,int right,int[][] dp){
        if(dp[left][right]!=-1) return dp[left][right];
        if(left>=right) return dp[left][right]=0;
        int min=Integer.MAX_VALUE;
        for(int x=left;x<=right;x++){
            int pay=Math.max(process(left,x-1,dp),process(x+1,right,dp))+x;
            min=Math.min(min,pay);
        }
        return dp[left][right]=min;
    }
}

运行结果

加个缓存表就是香,通过!

【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】_第4张图片

动态规划

求解思路

  1. 同理,核心求解思路我们上面已经讲过了,此处不同的是原来通过递归,此时我们通过dp数组和循环即可完成。

实现代码

继续改进!

class Solution {
    public int getMoneyAmount(int n) {
        int[][] dp=new int[n+5][n+5];
        for(int i=n;i>0;i--){
            for(int j=i+1;j<=n;j++){
                dp[i][j]=Integer.MAX_VALUE;
                for(int x=i;x<=j;x++){
                    dp[i][j]=Math.min(Math.max(dp[x+1][j],dp[i][x-1])+x,dp[i][j]);
                }
            }
        }
        return dp[1][n];
    }
}

运行结果

【LeetCode每日一题: 375. 猜数字大小 II | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】_第5张图片

共勉

最后,我想送给大家一句一直激励我的座右铭,希望可以与大家共勉!

在这里插入图片描述

你可能感兴趣的:(#,动态规划系列,LeetCode每日一题打卡,leetcode,动态规划,java)