算法学习——LeetCode力扣动态规划篇3(494. 目标和、474. 一和零、518. 零钱兑换 II)

news2024/12/23 22:17:40

算法学习——LeetCode力扣动态规划篇3

在这里插入图片描述

494. 目标和

494. 目标和 - 力扣(LeetCode)

描述

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 ‘+’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入:nums = [1], target = 1
输出:1

提示

1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000

代码解析

这道题根本还是回到了在数组中找到一个集合,使得该集合与其余部分之差为target,通过公式推导:
我们可以知道 该集合的值为:(sum-target)/2;

回溯法

目的是找到和为**(sum-target)/2** 的种类

class Solution {
public:
    int result = 0;
    void backtracking(vector<int>& nums, int target ,int deep ,int sum)
    {
        if(sum > target)return;
        if(sum == target)result++;
        if(deep == nums.size()) return;
        //从任一点开始
        for(int i= deep ; i < nums.size() ;i++)
        {
            backtracking(nums,target , i+1  , sum + nums[i]);
        }
        return;
    }
    int findTargetSumWays(vector<int>& nums, int target) {
       
        int sum = 0 , diff = 0;
        for(auto it:nums) sum += it;
        diff = sum - target;
        if( diff<0 || diff%2==1 ) return 0;
		//回溯找diff/2
        backtracking(nums,diff/2,0 ,0);
        return result;
    }
};

动态规划
  1. 背包定义: dp[i][j] , i是使用0-i的元素,j是背包容量,dp[i][j]是使用这么多个元素恰好凑成j的情况
  2. 初始化:dp[0][0]为1,装满容量为0的背包,有一种方法。dp[0][j],看第一个元素的大小情况,进行赋值1(如果第一个元素为0.则dp[0][0]应该为2),其他层的根据第一层改变.
  3. 遍历顺序:从上往下
  4. 递推公式: dp[i][j]=dp[i-1][j](不需要num[i]就能够凑出j的情况)+dp[i-1][j-nums[i]];(需要num[i]凑出j空间的情况) 最终就能实现,从0-i元素当中组合,得到target的所有情况。
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
       
        int sum = 0 , diff = 0;
        for(auto it:nums) sum += it;
        diff = sum - target;
        if( diff<0 || diff%2==1 ) return 0;
        vector<vector<int>>  dp( nums.size() , vector<int>(diff/2 + 1 , 0) ) ;

        dp[0][0] = 1;
        for(int j=0 ; j<(diff)/2+1 ; j++)
            if(j==nums[0]) dp[0][j] += 1;


        for(int i=1 ; i<nums.size() ;i++)
        {
            for(int j=0 ; j<(diff)/2+1 ; j++)
            {
                if(j>=nums[i])
                    dp[i][j] = dp[i-1][j] + dp[i-1][ j - nums[i]] ;
                else
                    dp[i][j] = dp[i-1][j];
            }
        }      
        return dp[nums.size()-1][(diff)/2];
    }
};

474. 一和零

474. 一和零 - 力扣(LeetCode)

描述

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例

示例 1:

输入:strs = [“10”, “0001”, “111001”, “1”, “0”], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {“10”,“0001”,“1”,“0”} ,因此答案是 4 。
其他满足题意但较小的子集包括 {“0001”,“1”} 和 {“10”,“1”,“0”} 。{“111001”} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

输入:strs = [“10”, “0”, “1”], m = 1, n = 1
输出:2
解释:最大的子集是 {“0”, “1”} ,所以答案是 2 。

提示

1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i] 仅由 ‘0’ 和 ‘1’ 组成
1 <= m, n <= 100

代码解析

动态规划(01背包,三级数组)

和经典的背包问题只有一种容量不同,这道题有两种容量,即选取的字符串子集中的 0 和 1 的数量上限。

经典的背包问题可以使用二维动态规划求解,两个维度分别是物品和容量。这道题有两种容量,因此需要使用三维动态规划求解,三个维度分别是字符串、0的容量和 1 的容量。

定义三维数组dp,其中dp[i][j][k] 表示在前 i 个字符串中,使用 j 个 0 和 k 个 1 的情况下最多可以得到的字符串数量。
当 0 和 1 的容量分别是 j 和 k 时,考虑以下两种情况:

  • 如果 j< zeros 或 k<ones,则不能选第 i 个字符串,此时有 dp[i][j][k] = dp[i−1][j][k];

  • 如果 j ≥ zeros 且 k ≥ones,则如果不选第 i个字符串,有dp[i][j][k]=dp[i−1][j][k],如果选第 i个字符串,有 dp[i][j][k]=dp[i−1][j−zeros][k−ones]+1,dp[i][j][k] 的值应取上面两项中的最大值。

因此状态转移方程如下:
在这里插入图片描述

class Solution {
public:
    int find_0(string s1)
    {
        int num = 0;
        for(auto it:s1) if(it == '0') num++;
        return num;
    }

    int findMaxForm(vector<string>& strs, int m, int n) {

        vector<vector<vector<int>>>  dp( strs.size() ,vector<vector<int>>( m+1 ,vector<int>( n+1,0) ));
        int num_0 = 0,num_1 = 0;
        num_0 = find_0(strs[0]);
        num_1 = strs[0].size() - num_0;
        for(int j=0 ; j<= m ;j++)
        {
            for(int k=0 ; k<= n ;k++)
            {
               
                if( j>= num_0 && k>= num_1)
                    dp[0][j][k] = 1;
            }
           
        }

        
        for(int i=1 ; i<strs.size() ; i++)
        {
            num_0 = find_0(strs[i]);
            num_1 = strs[i].size() - num_0;
            for(int j=0 ; j<=m ;j++)
            { 
                for(int k=0 ; k<=n ;k++)
                {
                    
                     if( j>= num_0 && k>= num_1)
                        dp[i][j][k] = max( dp[i-1][j][k], dp[i-1][j - num_0][k - num_1] + 1);
                     else
                        dp[i][j][k] = dp[i-1][j][k];
                }
            }
        }
        
        int max_num = 0;
        for(int i=0 ; i<strs.size() ; i++)
        {
            if(dp[i][m][n] > max_num) max_num = dp[i][m][n];
            // cout<<dp[i][m][n]<<' ';
        }
            
        return max_num ;
    }
};

动态规划(滑动数组,二级数组)

由于dp[i][][] 的每个元素值的计算只和dp[i−1][][] 的元素值有关,因此可以使用滚动数组的方式,去掉 dp 的第一个维度,将空间复杂度优化到 O(mn)O(mn)。

实现时,内层循环需采用倒序遍历的方式,这种方式保证转移来的是 dp[i−1][][] 中的元素值。

class Solution {
public:
    int find_0(string s1)
    {
        int num = 0;
        for(auto it:s1) if(it == '0') num++;
        return num;
    }

    int findMaxForm(vector<string>& strs, int m, int n) {

        vector<vector<int>>  dp( m+1 ,vector<int>(n+1,0));

        int num_0 = 0,num_1 = 0;
        for(int i=0 ; i<strs.size() ; i++)
        {
            num_0 = find_0(strs[i]);
            num_1 = strs[i].size() - num_0;
            for(int j=m ; j>=num_0;j--)
            { 
                for(int k=n ; k>=num_1 ;k--)
                {
                    dp[j][k] = max( dp[j][k], dp[j - num_0][k - num_1] + 1);
                }
            }
        }
        return dp[m][n] ;
    }
};

518. 零钱兑换 II

518. 零钱兑换 II - 力扣(LeetCode)

描述

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

示例

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。

示例 3:

输入:amount = 10, coins = [10]
输出:1

提示

1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins 中的所有值 互不相同
0 <= amount <= 5000

代码解析

完全背包

一看到钱币数量不限,就知道这是一个完全背包。
dp[j]:凑成总金额j的货币组合数为dp[j]

dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不考虑coins[i])相加。
所以递推公式:dp[j] += dp[j - coins[i]];

首先dp[0]一定要为1,dp[0] = 1是 递归公式的基础。
从dp[i]的含义上来讲就是,凑成总金额0的货币组合数为1。

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int> dp( amount+1 , 0 );

        dp[0] = 1 ;
        for(int i=0 ; i < coins.size() ; i++)
        {
            for(int j=0 ; j<=amount ; j++  )
            {
                if( j>=coins[i] )
                    dp[j] +=  dp[j-coins[i]] ;
                else
                    dp[j] = dp[j];
            }
        }
        return dp[amount];
    }
};

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

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

相关文章

【xinference】(8):在autodl上,使用xinference部署qwen1.5大模型,速度特别快,同时还支持函数调用,测试成功!

1&#xff0c;关于xinference https://www.bilibili.com/video/BV14x421U74t/ 【xinference】&#xff08;8&#xff09;&#xff1a;在autodl上&#xff0c;使用xinference部署qwen1.5大模型&#xff0c;速度特别快&#xff0c;同时还支持函数调用&#xff0c;测试成功&#…

系统IO函数接口

目录 前言 一. man手册 1.1 man手册如何查询 1.2 man手册基础 二.系统IO函数接口 三.open打开文件夹 3.1 例1 open打开文件 3.2 open打开文件代码 3.3 例2 创建文件 四.write写文件 4.1 write写文件 五. read读文件 5.1 read读文件与偏移 5.2 偏移细节 5.3 read读文件代码 六.复…

1,static 关键字.Java

目录 1.概述 2.定义格式和使用 2.1 静态变量及其访问 2.2 实例变量及其访问 2.3 静态方法及其访问 2.4 实例方法及其访问 3.小结 1.概述 static表示静态&#xff0c;是Java中的一个修饰符&#xff0c;可以修饰成员方法&#xff0c;成员变量。被static修饰后的&#xff…

STM32CubeMX配置步骤详解零 —— 引言

引子 初识 笔者接触STM32系列MCU有些年头了。初次接触是2015年&#xff0c;那时是在第二空间&#xff08;北京&#xff09;科技有限公司上班&#xff0c;是以STM32F407&#xff08;后缀好像是RGT6或ZGT6&#xff0c;记得不是很清楚了&#xff09;为主芯片做VR头戴式设备&…

40道Java经典面试题总结

1、在 Java 中&#xff0c;什么时候用重载&#xff0c;什么时候用重写&#xff1f; &#xff08;1&#xff09;重载是多态的集中体现&#xff0c;在类中&#xff0c;要以统一的方式处理不同类型数据的时候&#xff0c;可以用重载。 &#xff08;2&#xff09;重写的使用是建立…

githacker安装使用

githack下载不了文件&#xff0c;换个工具&#xff01; 项目地址 WangYihang/GitHacker: &#x1f577;️ A .git folder exploiting tool that is able to restore the entire Git repository, including stash, common branches and common tags. (github.com) 安装 pyth…

光伏行业项目管理系统解决方案!企智汇光伏项目管理系统!

光伏行业项目管理系统解决方案旨在通过整合和优化项目管理流程&#xff0c;提高光伏项目的执行效率和质量。以下是企智汇软件详细的光伏行业项目管理系统解决方案的框架&#xff1a; 一、系统概述 企智汇光伏行业项目管理系统是一个集项目规划、执行、监控和收尾于一体的综合…

Vue3:用Pinia的storeToRefs结构赋值store数据

一、情景描述 我们学习了Pinia之后&#xff0c;知道&#xff0c;数据是配置在Pinia的state里面的。 那么&#xff0c;如果有多个字段需要取出来使用&#xff0c;并且不丢失数据的响应式&#xff0c;如何优雅的操作了&#xff1f; 这里就用到了Pinia的storeToRefs函数 二、案…

【CANN训练营笔记】AscendCL图片分类应用(C++实现)

样例介绍 基于PyTorch框架的ResNet50模型&#xff0c;对*.jpg图片分类&#xff0c;输出各图片所属分类的编号、名称。 环境介绍 华为云AI1s CPU&#xff1a;Intel Xeon Gold 6278C CPU 2.60GHz 内存&#xff1a;8G NPU&#xff1a;Ascend 310 环境准备 下载驱动 wget ht…

CAPL实现关闭TCP连接的几种方式以及它们的区别

在讲正文前,我们有必要复习下关闭TCP连接的过程:四次挥手。 假设A和B建立TCP连接并进行数据传输,当A的数据发送完后,需要主动发起断开连接的请求: A发送FIN报文,发起断开连接的请求B收到FIN报文后,首先回复ACK确认报文B把自己的数据发送完,发送FIN报文,发起断开连接的…

探索网红系统功能菜单架构的设计与优化

随着社交媒体和数字化内容的普及&#xff0c;网红经济正在成为新兴的产业。在网红经济体系中&#xff0c;网红系统的功能菜单架构对于平台的用户体验和运营效率至关重要。本文将深入探讨网红系统功能菜单架构的设计与优化&#xff0c;为网红经济的发展提供新的思路和方法。 --…

HWOD:自守数

一、知识点 break只会结束最里面的一层循环 int型数按位比较的时候&#xff0c;可以直接求余比较&#xff0c;无需转换为char型数组后再按下标比较 二、题目 1、描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff1a;25^2 625&#xff0c;76^2 5776…

软考高级架构师:文件管理-位示图概念和例题

一、AI 讲解 文件管理在操作系统中负责文件的存储、检索、共享和保护。管理空闲空间是其中的一项重要任务&#xff0c;以确保文件系统的高效和灵活性。常见的空闲空间管理方法有空闲区表法、空闲链表法、位示图法和成组链表法。 下面通过表格形式概括这些方法的特点和应用场景…

Python快速入门系列-9(Python项目实战)

第九章:Python项目实战 9.1 开发一个简单的Web应用9.1.1 项目概述9.1.2 环境准备9.1.3 项目结构9.1.4 代码实现9.1.4.1 创建数据库模型9.1.4.2 创建视图9.1.4.3 实用工具函数9.1.4.4 运行应用9.1.5 模板设计9.2 数据分析与可视化项目9.2.1 项目概述9.2.2 环境准备9.2.3 数据分…

file_get_contents(‘php://input‘); 这个postman要如何传参

在 Postman 中传递参数给 file_get_contents(php://input); 是通过请求的 Body 部分来实现的。使用 Postman 进行 API 接口测试时&#xff0c;可以按照以下步骤来传递参数&#xff1a; 打开 Postman 并创建一个新的请求。在请求的 URL 地址栏输入你的 API 地址。选择请求方法为…

Spark实战:词频统计

文章目录 一、Spark实战&#xff1a;词频统计&#xff08;一&#xff09;Scala版1、分步完成词频统计2、一步搞定词频统计 &#xff08;二&#xff09;Python版1、分步完成词频统计2、一步搞定词频统计 二、实战总结 一、Spark实战&#xff1a;词频统计 &#xff08;一&#x…

【Python时序预测系列】基于ConvLSTM实现单变量时间序列预测(源码)

这是我的第252篇原创文章。 一、引言 ConvLSTM是一种融合了卷积神经网络&#xff08;CNN&#xff09;和长短期记忆网络&#xff08;LSTM&#xff09;的混合神经网络结构&#xff0c;专门用于处理时空序列数据。ConvLSTM结合了CNN对空间特征的提取和LSTM对时间序列建模的能力&a…

CentOS7安装flink1.17完全分布式

前提条件 准备三台CenOS7机器&#xff0c;主机名称&#xff0c;例如&#xff1a;node2&#xff0c;node3&#xff0c;node4 三台机器安装好jdk8&#xff0c;通常情况下&#xff0c;flink需要结合hadoop处理大数据问题&#xff0c;建议先安装hadoop&#xff0c;可参考 hadoop安…

曲线降采样之道格拉斯-普克算法Douglas–Peucker

曲线降采样之道格拉斯-普克算法Douglas–Peucker 该算法的目的是&#xff0c;给定一条由线段构成的曲线&#xff0c;找到一条点数较少的相似曲线&#xff0c;来近似描述原始的曲线&#xff0c;达到降低时间、空间复杂度和平滑曲线的目的。 附赠自动驾驶学习资料和量产经验&…

【C++】哈希之位图

目录 一、位图概念二、海量数据面试题 一、位图概念 假如有40亿个无重复且没有排序的无符号整数&#xff0c;给一个无符号整数&#xff0c;如何判断这个整数是否在这40亿个数中&#xff1f; 我们用以前的思路有这些&#xff1a; 把这40亿个数遍历一遍&#xff0c;直到找到为…