力扣 hot100 -- 动态规划(下)

news2024/9/21 16:49:25

目录

💻最长递增子序列

AC  动态规划

AC  动态规划(贪心) + 二分

🏠乘积最大子数组

AC  动规

AC  用 0 分割

🐬分割等和子集

AC  二维DP

AC  一维DP

⚾最长有效括号

AC  栈 + 哨兵


💻最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)

子序列:不用连续

子串:要求连续

AC  动态规划

时间 O(n^2)

/*
dp[i] : 第 i 个元素结尾的最长子序列长度(下标0开始)
dp[i] = max(dp[i], dp[j] + 1)
初始化 : dp[i] = 1
*/
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n + 1, 1);
        for (int i = 1; i < n; ++i)
            for (int j = 0; j < i; ++j) 
                if (nums[j] < nums[i])
                    dp[i] = max(dp[i], dp[j] + 1);
        int ans = 1;
        for (auto x : dp)
            ans = max(ans, x);
        return ans;
    }
};

AC  动态规划(贪心) + 二分

二分实现 O(logn) 查找,为了使用二分,我们需要让 dp[] 数组有序,所以需要改变 dp[] 数组的含义(状态)

贪心策略:tails 中存储的元素越小,上升的子序列越长 

举例解释

nums[] = {7, 8, 9, 1, 2, 3, 4, 5};

遍历完 7 8 9 后 tails[] = {7, 8, 9};

接着遍历到 1,那么二分查找 tails[],找到第一个比 tails 大的位置,即 7,替换后变成

tails[] = {1, 8, 9};

如果没有比当前 nums[] 值大的元素,直接加到后面

最后输出 tails[] 长度,就是最长上升子序列长度

时间 O(nlogn)

/*
tails[i] : 长度 i+1 子序列的尾部元素
1)nums[] 中当前元素 x > tails.back(), x 插入 tails 最后
2)否则, 二分查找 tails[] 中第一个 > x 的元素, 替换成 x
最后返回 tails[] 大小
*/
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> tails;
        tails.push_back(nums[0]);

        for (auto x : nums) {
            if (x > tails.back()) {
                tails.push_back(x);
                continue;
            }
            int l = 0, r = tails.size() - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (tails[mid] < x)
                    l = mid + 1;
                else
                    r = mid;
            }
            tails[l] = x;
        }
        return tails.size();
    }
};
// 检验二分边界
// tails[]: 1 3 5 -- x: 3/4
// tails[]: 1 3 5 7 -- x: 3/4/5

🏠乘积最大子数组

152. 乘积最大子数组 - 力扣(LeetCode)

注意是“连续子数组” 

AC  动规

1)滚动

本题,dp[i] 都是基于 dp[i -1] 得到的,所以可以将一维数组变成一个变量,即 “滚动数组” 

2)坑

遍历数组,更新 3 个 dp 变量时,maxDp 基于上一个 maxDp 没问题

但是 maxDp 更新后,minDp 还是基于上一个 maxDp

所以需要一个临时变量保存上一个 maxDp

然后 dp 可以直接基于新的 maxDp

3)坑2

题目保证 32 位,也就是 10^9,但是,样例里有一组 10^19 次方的....

所以,有 4 个地方要加 double,防止类型不匹配 或 heap flow(堆溢出)

时间 O(n)

/*
滚动数组,一维数组变变量
maxDp[i] : 第 i 个元素结尾的最大值
minDp[i] : 第 i 个元素结尾的最小值
dp[i] : 只选前 i 的元素的最大值
*/
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if (n == 1)
            return nums[0];
        double maxDp = nums[0], minDp = nums[0], dp = nums[0];
        for (int i = 1; i < n; ++i) {
            double t = maxDp; // 临时变量
            maxDp = max(max((double)nums[i], maxDp*nums[i]), minDp*nums[i]);
            minDp = min(min((double)nums[i], t*nums[i]), minDp*nums[i]);
            dp = max(dp, maxDp); // 上一个 dp 和 新的 maxDp 取较大值
        }
        return (double)dp;
    }
};

AC  用 0 分割

用 0 分割成多个连续的子数组,对每个子数组:

1)偶数个负数,直接相乘(负数数量 0, 2, 4, 6...)

2)奇数个负数:

        a. 左到右相乘,直到最后一个负数之前

        b. 右到左,直到最后一个负数之前

取 a. b. 的 max()

3)实际遍历中,先左到右遍历,后右到左遍历,单次遍历中,只需要动态更新最大值(包含了偶数,奇数个负数的两种情况)

时间 O(n)

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        double ans = nums[0];
        double t = 1; // 临时变量保存乘积
        
        // 左到右
        for (int i = 0; i < nums.size(); ++i) {
            t *= nums[i];
            ans = max(ans, t);
            if (t == 0)
                t = 1; // 用 0 分割子数组
        }
        // 右到左
        t = 1;
        for (int i = nums.size() - 1; i >= 0; --i) {
            t *= nums[i];
            ans = max(ans, t);
            if (t == 0)
                t = 1;
        }
        return (int)ans;
    }
};

🐬分割等和子集

416. 分割等和子集 - 力扣(LeetCode)

AC  二维DP

01背包画表格类似这样

和为奇数,直接返回 false,否则打表会发现,出现了一些奇怪的错误

含义

dp[i][j] : 只从 [0, i] 区间里选,每个数最多选 1 次,和为 j

递推式

选第 i 个:dp[i - 1][j - nums[i]]

不选第 i 个:dp[i - 1][j]

第 i 个数 == 总和的一半

dp[i][j] = dp[i - 1][j - nums[i]] || dp[i - 1][j] || (nums[i] == sum/2)

初始化

根据递推式,只需初始化第 0 行,即只从 [0, 0] 区间选,和为 nums[0] 的 == 1,其他为 0

输出

dp[n - 1][sum / 2]:表示从 [0, n - 1] 选, 和为总和一半, 即等和子集

O(n * sum/2)

// dp[i][j] = dp[i - 1][j - nums[i]] || dp[i - 1][j] || (nums[i] == sum/2)
// 输出 dp[n - 1][sum / 2]
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0, n = nums.size();
        for (auto x : nums)
            sum += x;
        if (sum % 2 == 1)
            return false; // 和为奇数

        // n 行, 每一行就是 vector<int>(), 这一行表示总和 0 ~ sum/2, 初始化为 0
        vector<vector<int>> dp(n, vector<int>(sum / 2 + 1, 0));

        if (nums[0] <= sum/2)
            dp[0][nums[0]] = 1; // 从 [0, 0] 选, 和为nums[0]

        for (int i = 1; i < n; ++i)
            for (int j = 0; j <= sum/2; ++j) {
                dp[i][j] = dp[i - 1][j] || (nums[i] == sum/2);
                if (j >= nums[i]) // 防止越界
                    dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i]];
            }

        return dp[n - 1][sum / 2];
    }
};

AC  一维DP

考虑到递推式 dp[i][j] 都是来源于 dp[i - 1][...],可以将二维变成一维,优化空间👇

那么为什么要逆序遍历子集的和 j 呢,因为,dp[j] 都是基于上一行的,旧的(未被修改的) dp[j] 和 dp[j - nums[i]]

如果顺序遍历,dp[j - nums[i]] 会被多次修改,也就是取了多个元素,而题目规定只能取一个

顺序遍历适合完全背包,而不是 01 背包

 

// dp[j] :和为 j
// dp[j] = dp[j - nums[i]] || dp[j] || (nums[i] == sum/2)
// 输出 dp[sum / 2]
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0, n = nums.size();
        for (auto x : nums)
            sum += x;
        if (sum % 2 == 1)
            return false; // 和为奇数

        // 和的一半 +1 个元素
        vector<int> dp(sum / 2 + 1, 0);

        if (nums[0] <= sum/2)
            dp[nums[0]] = 1; // 从 [0, 0] 选, 和为nums[0]

        for (int i = 1; i < n; ++i)
            for (int j = sum/2; j >= 0; --j) {
                dp[j] = dp[j] || (nums[i] == sum/2);
                if (j >= nums[i]) // 防止越界
                    dp[j] = dp[j] || dp[j - nums[i]];
            }
        return dp[sum / 2];
    }
};

⚾最长有效括号

32. 最长有效括号 - 力扣(LeetCode)

AC  栈 + 哨兵

求连续的最长有效括号

如果不连续,栈就会被清空最后一个元素,再插入新的下标,即更新了栈顶的元素

初始插入 -1(哨兵),防止先遇到右括号,栈为空就 pop 导致的栈溢出

时间 O(n)

class Solution {
public:
    int longestValidParentheses(string s) {
        int ans = 0;
        if (s.size() == 0) return 0;

        stack<int> st;
        st.push(-1); // 防止溢出, 为后面的连续准备

        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == '(') // 左括号
                st.push(i); 
            else { // 右括号
                st.pop();
                if (st.empty())
                    st.push(i);
                else 
                    ans = max(ans, i - st.top()); // 连续的长度
            }
        }
        return ans;
    }
};

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

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

相关文章

GPT-4o不香了, Claude3.5 Sonnet来了,直接免费可用

大家好&#xff01;我是YUAN。 刚刚&#xff01; AI领域又迎来了一场新的风暴——Anthropic公司发布了全新的Claude 3.5 Sonnet模型&#xff0c;这一消息如同一颗重磅炸弹&#xff0c;震撼了整个科技界。 Claude 3.5 Sonnet与GPT-4o对比 性能飞跃&#xff1a;超越GPT-4o Cl…

如何修改node_modules里的代码

为什么要改node_modules&#xff1f; 在平常的开发中&#xff0c;其实是很少需要改 node_modules 里的代码的。但是如果npm包有点小问题或者不符合我们的场景。 应该怎么改才能是最好的呢&#xff1f; 方法一&#xff1a;直接改 这种很好懂&#xff0c;就是直接进 node_modu…

SpringBoot使用RedisTemplate、StringRedisTemplate操作Redis

前言 RedisTemplate 是 Spring Boot 访问 Redis 的核心组件&#xff0c;底层通过 RedisConnectionFactory 对多种 Redis 驱动进行集成&#xff0c;上层通过 XXXOperations 提供丰富的 API &#xff0c;并结合 Spring4 基于泛型的 bean 注入&#xff0c;极大的提供了便利&#x…

D-DPCC: Deep Dynamic Point Cloud Compression via 3D Motion Prediction

1. 论文基本信息 发布于&#xff1a; 2022 2. 创新点 首先提出了一种端到端深度动态点云压缩框架(D-DPCC)&#xff0c;用于运动估计、运动补偿、运动压缩和残差压缩的联合优化。提出了一种新的多尺度运动融合(MMF)模块用于点云帧间预测&#xff0c;该模块提取和融合不同运动流…

网络安全----防御----防火墙安全策略组网

防火墙组网 要求&#xff1a; 1&#xff0c;DMz区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 2&#xff0c;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff0c;办公区设备10.0.…

3d模型选不中任何东西是什么原因?---模大狮模型网

在进行3D模型设计过程中&#xff0c;有时会遇到无法选择模型中的任何元素的问题。这种情况可能会影响设计师的工作效率和体验&#xff0c;因此了解问题的原因以及如何解决是至关重要的。本文将探讨在3D建模中遇到无法选中模型元素的原因及解决方法。 一、问题原因分析 无法选中…

1.9-改进的CBOW模型的实现

文章目录 0引言1 CBOW模型的重构1.1模型初始化1.2模型的前向计算1.3模型的反向传播 2总结 0引言 前面讲述了对word2vec高速化的改进&#xff1a; 改进输入侧的计算&#xff0c;变成Embedding&#xff0c;即从权重矩阵中选取特定的行&#xff1b;改进输出侧的计算&#xff0c;包…

最新的数据防泄密方案来袭!

沙箱技术作为一种先进的数据安全解决方案&#xff0c;在数据防泄密领域发挥着日益重要的作用。它通过构建一个隔离的虚拟环境&#xff0c;使得应用程序在该环境中运行&#xff0c;从而隔离了应用程序对系统资源的直接访问&#xff0c;有效防止了数据泄露的风险。 一、沙箱技术在…

[C++] 轻熟类和对象

类的定义 格式规范 class为定义类的关键字&#xff0c;后有类名&#xff0c;类的主体存于{}中&#xff1b;类定义结束时后面的分号不能省略&#xff1b;类体的内容成为类的成员&#xff0c;类中的变量成为成员变量&#xff0c;函数成为方法或成员函数&#xff1b;C兼容C语言的…

[spring] Spring MVC - security(上)

[spring] Spring MVC - security&#xff08;上&#xff09; 这部分的内容基本上和 [spring] rest api security 是重合的&#xff0c;主要就是添加 验证&#xff08;authentication&#xff09;和授权&#xff08;authorization&#xff09;这两个功能 即&#xff1a; 用户…

SpringBoot的老年慢性病药物管理系统-计算机毕业设计源码70568

目录 摘要 Abstract 第一章 绪论 1.1 选题背景及意义 1.2 国内外研究现状 1.3 研究方法 第二章 相关技术介绍 2.1 MySQL简介 2.2 Java编程语言 2.3 B/S模式 2.4 springboot框架 第三章 老年慢性病药物管理系统 系统分析 3.1 系统目标 3.2 系统可行性分析 3.2.1 技…

STM32中断学习记录

文章目录 NVICNVIC是什么NVIC寄存器NVIC 结构体NVIC 相关固件库函数 如何定义优先级中断编程外部中断 EXTIEXIT 外部中断/事件控制器EXIT的使用EXTI内部寄存器分析GPIO触发中断例程为什么中断后要清除中断标志位 SysTick的使用SysTick分析 NVIC NVIC是什么 待补充.........NVI…

ChatTTS的爆火是必然,它正在重新定义我们与机器对话的方式

当AI技术与语音合成相遇&#xff0c;开源技术众多&#xff0c;为什么 ChatTTS 能够一夜爆火&#xff1f;你有听说过能说情感真切文字的 AI 吗&#xff1f; 前言 想象一下&#xff0c;你只需输入一句话&#xff0c;AI就能念得声情并茂&#xff0c;不仅支持中英文混读&#xff0…

自注意力简介

在注意力机制中&#xff0c;每个查询都会关注所有的键值对并生成一个注意力输出。如果查询q&#xff0c;键k和值v都来自于同一组输入&#xff0c;那么这个注意力就被称为是自注意力&#xff08;self-attention&#xff09;。自注意力这部分理论&#xff0c;我觉得台大李宏毅老师…

一位互联网公司项目经理繁忙的一天

早晨&#xff1a;准备与计划 7:00 AM - 起床与准备 项目经理起床后&#xff0c;快速洗漱并享用早餐。之后花几分钟查看手机上的邮件和消息&#xff0c;确保没有紧急事务需要立即处理。 7:30 AM - 通勤时间 前往公司。在通勤途中&#xff0c;通过手机或平板电脑查看当天的会议…

硅谷甄选运营平台-vue3组件通信方式

vue3组件通信方式 vue2组件通信方式&#xff1a; props:可以实现父子组件、子父组件、甚至兄弟组件通信自定义事件:可以实现子父组件通信全局事件总线$bus:可以实现任意组件通信pubsub:发布订阅模式实现任意组件通信vuex:集中式状态管理容器&#xff0c;实现任意组件通信ref:父…

简单了解下安全测试!

一、基本概念 安全测试是在软件产品开发基本完成时&#xff0c;验证产品是否符合安全需求定义和产品质量标准的过程。它主要检查系统对非法侵入渗透的防范能力&#xff0c;旨在通过全面的脆弱性安全测试&#xff0c;发现系统未知的安全隐患并提出相关建议&#xff0c;确保系统…

星申刹车盘平衡机:精准与高效兼备

星申动双工位刹车盘动平衡机是一款具备测量和切削两个工位的高精度设备。该机器由平衡测量单元、内部搬运系统、切削校正模块及电气控制部分组成&#xff0c;专为满足自动化生产需求设计。其主要功能特点包括&#xff1a; 1. 实现全自动刹车盘平衡测试&#xff0c;精度高达30gm…

vue3 ts 报错:无法找到模块“../views/index/Home.vue”的声明文件

解决办法&#xff1a; env.d.ts 新增代码片段&#xff1a; declare module "*.vue" {import type { DefineComponent } from "vue";// eslint-disable-next-line typescript-eslint/no-explicit-any, typescript-eslint/ban-typesconst component: Define…

ExtruOnt——为工业 4.0 系统描述制造机械类型的本体

概述 论文地址 &#xff1a;https://arxiv.org/abs/2401.11848 原文地址&#xff1a;https://ai-scholar.tech/articles/ontology/ExtruOnt 在工业 4.0 应用场景中&#xff0c;以机器可解释代码提供的、语义丰富的制造机械描述可以得到有效利用。然而&#xff0c;目前显然还缺…