java算法day27

news2024/9/17 8:57:20

java算法day27

  • 动态规划初步总结
  • 509 斐波那契数
  • 杨辉三角
  • 打家劫舍
  • 完全平方数

动态规划初步总结

如果你感觉某个问题有很多重叠子问题,使用动态规划是最有效的。
动态规划的过程就是每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心了。贪心是“直接”从局部选最优的。

看到目前的各种教程,目前能看懂的动态规划思想总结就是:
这三步:
1、穷举法(暴力搜索)
2、记忆化搜索(剪枝)
3、改写成迭代形式。

目前我只能一步步的做题来体会动态规划。


509 斐波那契数列

目前就拿着上面总结的思想来做做题。

拿到这个题,我上来就想到了递归解法(这也对应着上面的第一点)。然后快速就交了,过了,但是超越百分之5。足以见得效率非常的低。

class Solution {
    public int fib(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1){
            return 1;
        }

        return fib(n-2) + fib(n-1);
    }
}

问题出在哪里,从递归树里就清楚了
在这里插入图片描述
从这个计算过程可以看到,存在着大量的重复计算。比如计算f(18)和f(19)的时候,都会计算f(17),而计算f(17)的过程又需要往下递归,意思说f(17)要算两次。往下那肯定存在更多的重复性计算。所以说这是需要优化的点。

如何优化,如何实现快速访问,这里我们可以想到哈希,下次我要计算之前,我先不着急递归,我先去hash里面看看有没有现成的,直接哪来用。那么按照这样的想法我们就可以创建一个哈希表,至于这个表是什么样的,可以根据题目来。

有时候可能还想不通,那这个hash里面的值是怎么记录下来的,那我只能说要把递归的过程想清楚。
通过上面的代码,算f(5) return f(4) + f(3) 。那么按程序执行顺序来说,肯定是先进f(4),然后一直往下走
比如f(4) return f(3) + f(2)
f(3) = f(2) + f(1)
然后f(2) = f(1)+f(0) 。可以见得,在不断下去的过程中,f(4),f(3),f(2),f(1),f(0)都会计算。所以说在这最左边的分支,其实就已经把别的分支那些重复的点全计算完了。所以hash就是在这里就完成了计算,怎么算?这个过程中程序要进行计算,hash表直接把这个结果也存到自己的哈希表里不就完事了。

从这个过程,再对上面的递归树做一个优化,你可以看到这样的变化。
在这里插入图片描述
是不是感觉2^n级别的复杂度立马变o(n)了。
在这里插入图片描述
带备忘录的写法如下:

class Solution {


    public int fib(int n) {
        if(n<1){
            return 0;
        }
        int[] memo = new int[31];

        return helper(n,memo);
    }


    int helper(int n,int[] memo){
        if(n == 1 || n == 2){
            return 1;
        }
        if(memo[n]!=0){
            return memo[n];
        }
        memo[n] = helper(n-1,memo)+helper(n-2,memo);
        return memo[n];
    }

    
}

这么这就是dp了吗?还不是!
这其实还是一个自顶向下的解法。

真正的dp是什么。真正的dp是自底向上,从最小的子问题开始,然后逐步构造最大的解,直到达到目标。

动态规划的本质:动态规划的核心是通过解决子问题来解决更大的问题,在斐波那契数的例子中,我们直到每个数都是前两个数的和。

所以这里可以总结出动态规划问题的真正含义了。
我先来说说动态规划是如何解决这个问题的,首先如果清楚子问题是什么样的,然后清楚子问题的初状态,那么我就能够直接从这个子问题出发,不断地进行状态运算,直到状态转移到最终结果。然后这个得到下一个状态的方法,就是所谓的状态转移方程。

所以这里可以总结一个结论:
也就是很多教程里面教的方法:
子问题的识别
正如你所说,清楚地识别子问题是关键。在斐波那契数列中,子问题就是计算每个 F(i)。

初始状态(基本情况)
这些是已知的最小子问题的解。在斐波那契数列中,F(0) = 0 和 F(1) = 1。

状态转移
这是从一个子问题到另一个子问题的过程。在斐波那契数列中,状态转移方程是 F(i) = F(i-1) + F(i-2)。

最终状态
这是我们最终要求解的问题。在斐波那契数列中,就是计算 F(n)。

从初始状态到最终状态
正如你所说,我们可以从初始状态开始,通过不断应用状态转移方程,最终达到我们想要的结果。

说的更直白一点:
也就是说,如果我在做题的过程中,搞清楚了什么是子问题,还有初始状态,知道下一个状态该如何正确计算。那么我就能从这个初始状态直接往后推,直到推出最后的正确答案。


然后就立马写出了这个题。感觉还是非常清楚的。
子问题怎么找? 这里我看网上一般是通过推广的办法,由f(n)来思考那么是要计算f(n-1)+f(n-2)。那么推广到i就是dp[i] = dp[i-1]+dp[i-2];所以子问题就是计算dp[i-1]和dp[i-2]。往最初的状态倒就是从dp[0] 和 dp[1]开始
状态转移方程是啥? 就是怎么计算下一个状态,这里状态转移方程就是dp[i] = dp[i-1]+dp[i-2]
最终状态怎么确定? 就是看dp要到哪停下来。这里就是算dp[n]

dp数组到底怎么初始化?这个我认为一是要根据问题,而是要根据数据的边界。即最大可能取到的状态来确定长度。

class Solution {
    public int fib(int n) {
        //快速特判
        if(n<2){
            return n;
        }

        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;

        for(int i = 2;i<=n;i++){
            dp[i] = dp[i-1]+dp[i-2];
        }

        return dp[n];
    }
}

提交之后会发现,效率和备忘录那个写法的效率相同
因为这俩的计算纯粹是反过来的关系

然后还可以再进一步优化

是不是发现我们其实只要这个最后的dp[n],甚至感觉这个dp数组有点多余了。
确实是,我们其实就只需要不断的迭代更新后面两个数字 即 dp[i-1] 和 dp[i-2]
这个技巧就是所谓的状态压缩 空间复杂度直接优化为o1了。
怎么理解状态压缩的应用?就是想想原来的dp数组,有没有一些空间是不必要存储的。

所以这里还有一个究极版本。

class Solution {
    public int fib(int n) {
        if(n<2){
            return n;
        }

        int pre = 0;
        int cur = 1;
        for(int i = 2;i<=n;i++){
            //sum是下一个状态
            int sum = pre+cur;
            pre = cur;
            cur = sum;
        }
        return cur;

    }
}

零钱兑换

上面的斐波那契还体现不出dp。因为没有求最值问题,现在来看看这个题。
我第一想法就是一个大回溯直接爆搜。果不其然第32个例子直接超时。

接下来就只能看看题解了,用dp来做这个题。

这里得到第一个知识点:能用dp,首先要复合最优子结构,子问题间必须互相独立。
啥叫互相独立,就是子问题之间没有互相影响。
简单来说就是考试,你要拿最高分,比如一共两名,语文和数学。
要拿最高分就是数学考最高,语文考最高。这样就叫独立。
如果你数学考得高了,会导致你语文考不高,那就不叫独立。

所以要自己看看子问题之间有没有互相制约关系,是否相互独立

还有这个看待子问题的角度也非常重要。有时候你子问题找错了,那就可能做不出来了。
对于本题而言,子问题是这样拆分的,比如追求amont = 11(原问题),如果你知道凑出amont = 10的最少硬币数(子问题),那么只需要把子问题的答案(再选一枚面值为1的硬币),就是原问题的答案。还有这怎么看出子问题之间没有互相限制,因为硬币数量是没有限制的。


这里又纠正了我看待动态规划问题的思路了。一开始我是没理解倒这个问题中的独立。
1、动态规划的思考方向:
首先,动态理解是要自底向上思考的,而不是从amount=11开始往下想,我从大的开始想,那么我就会老是去想我最后一个面值为1了,那不是有可能对我前面的问题产生影响?
这里主要是方向想错了
2、子问题的定义:
对于金额i,子问题是凑出金额i所需的最少硬币数
3、独立性本质:
当我们说子问题是独立的,我们指的是,求解金额i的最优解,不依赖于如何求解i+1,i+2等更大的金额。(说白了还是方向看错了)。
4、为什么看起来不独立(我之前的思想):
因为我方向想反了。

现在来模拟这个问题
举例说明:
假设硬币面值为 [1, 2, 5],我们要凑出 11。

我们首先解决小额问题:1, 2, 3, 4, 5, …
当我们到达 11 时,我们考虑的是:
dp[11] = min(dp[10] + 1, dp[9] + 1, dp[6] + 1)
这里的 dp[10], dp[9], dp[6] 都已经是各自最优的解了
我们不是在考虑 “用1个1硬币然后解决10”,而是在比较 “10的最优解+1” 和其他可能性

独立性的证明:

如果 dp[10] 是最优的(假设是3个硬币),那么无论我们如何解决 11,都不会影响 10 的这个最优解。
即使我们选择了 “dp[9] + 1个2硬币” 作为 11 的最优解,这也不会改变 10 的最优解仍然是 3 个硬币这个事实。

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

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

相关文章

热力图大揭秘!Matplotlib教你如何画出让数据‘火辣辣‘的激情图!

1. 引言 嘿&#xff0c;小伙伴们&#xff01;今天咱们来点不一样的&#xff0c;走进Matplotlib的神奇世界&#xff0c;一起绘制那让人热血沸腾的热力图&#xff01;别误会&#xff0c;这可不是什么天气预报图&#xff0c;而是让数据“火辣辣”展现自我的秘密武器。想象一下&am…

PHP进阶-CentOS7部署LNMP服务架构的项目

在开发和部署Web应用时&#xff0c;LNMP&#xff08;Linux、Nginx、MySQL、PHP&#xff09;的组合是非常常见的。这篇博客将介绍如何通过一个简单的脚本&#xff0c;在CentOS 7上部署LNMP&#xff0c;并将PHP项目自动部署到服务器上。这不仅可以节省大量的时间&#xff0c;还能…

《系统架构设计师教程(第2版)》第13章-层次式架构设计理论与实践-03-中间层(业务层|逻辑层)架构设计

文章目录 1. 业务逻辑层组件设计1.1 业务逻辑组件的实现类1.2 业务逻辑组件的配置 2. 业务逻辑层工作流设计2.1 工作流2.2 工作流参考模型2.2.1 概述2.2.1 工作流参考模型 3. 业务逻辑层实体设计3.1 业务逻辑层实体概述3.2 逻辑层实体的表示方法3.2.1 XML表示业务层实体3.2.2 通…

Prometheus+Grafana 监控平台实践-搭建常用服务监控告警

前言 Prometheus 是一个开放性的监控解决方案,通过各种 Exporter 采集当前主机/服务的数据,和 Grafana 相结合可以实现强大的监控和可视化功能 本篇将分享使用 docker compose 构建 Prometheus+Grafana,并监控之前文章所搭建的主机&服务,分享日常使用的一些使用经验 文…

Qt基础 | UDP通信 | UDP单播、广播、组播的介绍与实现

文章目录 一、QUdpSocket 实现 UDP 通信1.UDP 通信概述2.UDP 单播和广播2.1 主窗口类定义和构造函数2.2 UDP通信实现 3.UDP 组播3.1 主窗口类定义和构造函数3.2 组播功能的程序实现 Qt 网络模块&#xff1a; Qt基础 | 主机信息查询 | QHostInfo的介绍和使用 | QNetworkInterfac…

排序算法:选择排序,golang实现

目录 前言 选择排序 代码示例 1. 算法包 2. 选择排序代码 3. 模拟排序 4. 运行程序 5. 从大到小排序 循环细节 外层循环 内层循环 总结 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 选择排序的适用场景 1. 数据规模…

SAP PowerDesigner@官网下载

背景 略 问题 略 解决 用户可以通过访问SAP支持网站的首页&#xff08;‌https://support.sap.com/home.html&#xff09;‌&#xff0c;‌然后导航到“Software Downloads”&#xff08;‌软件下载&#xff09;‌部分来访问SAP软件的下载入口。‌在这里&#xff0c;‌用户可…

HCIP笔记1

hcia复习 osi--开放式系统互联参考模型---7层参考模型 tcp/ip协议栈道---4或5层 osi: 应用层 抽象语言-->编码 表示层 编码-->二进制 会话层 提供应用程序的会话地址 上三层为应用程序对数据流量进行加工及处理的阶段 传输层 分段、端口号 tcp/udp 网…

Apache2 Ubuntu-XXE漏洞渗透

Apache2 Ubuntu-XXE漏洞渗透 Apache2 Ubuntu Default Page 是一个包含xxe漏洞的页面&#xff0c;如何找到和利用xxe漏洞&#xff0c;并找到flag呢&#xff1f; 第一步&#xff1a;先打开其网页 当安装好虚拟机环境后&#xff0c;打开虚拟机我们并不知道它linux的账号密码 因…

通配符https证书的申请途径和配置方法

一、通配符SSL证书的功能 通配符SSL证书&#xff0c;也被称为泛域名证书&#xff0c;是一种特殊类型的SSL证书&#xff0c;它能够保护一个主域名及其所有次级子域名&#xff08;不可跨级保护&#xff09;。例如&#xff0c;如果您的主域名是example.com&#xff0c;那么一个通…

Vue2从基础到实战(v-bind对于样式控制的增强-操作style,v-model在其他表单元素的使用)

v-bind对于样式控制的增强-操作style 语法&#xff1a;style"样式对象" <div class"box" :style"{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div> 代码解析&#xff1a; HTML结构&#xff1a; 包含了一个div元素&…

什么是数据血缘?怎么做好数据血缘分析?

目录 一、什么是数据血缘&#xff1f; 二、数据血缘关系的四大特征 三、数据血缘分析怎么做&#xff1f; 1.定义元数据模型 2.收集元数据 3.建立血缘关系模型 4.追踪数据流动 5.可视化分析 6.集成到数据治理中 7.持续更新和维护 8.应用分析结果 四、数据血缘技术趋势 1.通用的血…

51单片机-第六节-LED点阵屏与_74HC595_

1.LED点阵屏的结构&#xff1a; 与数码管相同&#xff08;数码管只是把LED排成8字结构&#xff09;&#xff0c;8*8的点阵屏有8816个引脚。 双色点阵屏有82*824个引脚&#xff0c;结构如图&#xff1a; 注&#xff1a;点阵屏引脚多为乱序排列&#xff0c; 控制需看单片机说…

基于SpringBoot+Vue的大学生租房系统(带1w+文档)

基于SpringBootVue的大学生租房系统(带1w文档) 基于SpringBootVue的大学生租房系统(带1w文档) 该系统主要实现了用户和房主通过系统注册用户&#xff0c;登录系统后能够编辑自己的个人信息、查看首页&#xff0c;房屋信息&#xff0c;房屋评价&#xff0c;公告资讯&#xff0c;…

Linux第七节课gcc与g++

一、补充权限 普通用户无法执行sudo&#xff1a; 通过sudo执行后显示不在sudoers file中&#xff01;&#xff08;张三不被信任&#xff01;&#xff09; 需要修改配置文件&#xff08;白名单&#xff01;&#xff09; 配置文件位于以下目录&#xff1a; ls /etc/sudoers -…

[Day 40] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

強化學習概述 強化學習&#xff08;Reinforcement Learning, RL&#xff09;是一種機器學習方法&#xff0c;主要用於訓練智能體&#xff08;agent&#xff09;在特定環境&#xff08;environment&#xff09;中進行決策。智能體通過嘗試和錯誤來學習&#xff0c;以最大化其累…

【iOS】—— iOS持久化

iOS持久化 1. 数据持久化的目的2. iOS持久化的方案3. 数据持久化方式的分类内存缓存磁盘缓存 4. 沙盒机制5. 沙盒的目录结构获取应用程序的沙盒路径每次编译代码会生成新的沙盒路径&#xff0c;每次运行获得的沙盒路径都不一样。访问沙盒目录常用C函数介绍沙盒目录介绍 6. 持久…

浅谈线程组插件之bzm - Arrivals Thread Group

浅谈线程组插件之bzm - Arrivals Thread Group bzm - Arrivals Thread Group 是 JMeter 中的一个高级插件&#xff0c;由 BlazeMeter 提供&#xff0c;旨在为性能测试提供更灵活、更贴近实际场景的负载生成方式。与传统的线程组不同&#xff0c;Arrivals Thread Group 通过控制…

网上订餐系统2024((代码+论文+ppt)

网上订餐系统2024((代码论文ppt),编号:sp006 代码经过修正,确保可以运行,下载地址在文末 技术栈: springbottvuemysql 展示: 下载地址: CSDN现在上传有问题,有兴趣的朋友先收藏.正常了贴上下载地址 备注: 专业承接各种程序java,c,c,python,cuda,AI 运行有问题请私信我,…

互联网医院系统源码与医保购药APP开发的完整技术指南

本篇文章&#xff0c;笔者将详细介绍互联网医院系统与医保购药APP的开发全过程&#xff0c;帮助开发者理解其技术要点和实现路径。 一、互联网医院系统开发 1.需求分析与系统设计 需要明确系统的功能需求&#xff0c;如在线问诊、预约挂号、电子病历管理、远程医疗、支付系统…