【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和

这篇具有很好参考价值的文章主要介绍了【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文涉及知识点

动态规划 区间dp 位运算

LeetCode100259. 划分数组得到最小的值之和

给你两个数组 nums 和 andValues,长度分别为 n 和 m。
数组的 值 等于该数组的 最后一个 元素。
你需要将 nums 划分为 m 个 不相交的连续 子数组,对于第 ith 个子数组 [li, ri],子数组元素的按位AND运算结果等于 andValues[i],换句话说,对所有的 1 <= i <= m,nums[li] & nums[li + 1] & … & nums[ri] == andValues[i] ,其中 & 表示按位AND运算符。
返回将 nums 划分为 m 个子数组所能得到的可能的 最小 子数组 值 之和。如果无法完成这样的划分,则返回 -1 。
示例 1:
输入: nums = [1,4,3,3,2], andValues = [0,3,3,2]
输出: 12
解释:
唯一可能的划分方法为:
[1,4] 因为 1 & 4 == 0
[3] 因为单元素子数组的按位 AND 结果就是该元素本身
[3] 因为单元素子数组的按位 AND 结果就是该元素本身
[2] 因为单元素子数组的按位 AND 结果就是该元素本身
这些子数组的值之和为 4 + 3 + 3 + 2 = 12
示例 2:

输入: nums = [2,3,5,7,7,7,5], andValues = [0,7,5]

输出: 17

解释:

划分 nums 的三种方式为:

[[2,3,5],[7,7,7],[5]] 其中子数组的值之和为 5 + 7 + 5 = 17
[[2,3,5,7],[7,7],[5]] 其中子数组的值之和为 7 + 7 + 5 = 19
[[2,3,5,7,7],[7],[5]] 其中子数组的值之和为 7 + 7 + 5 = 19
子数组值之和的最小可能值为 17

示例 3:

输入: nums = [1,2,3,4], andValues = [2]

输出: -1

解释:

整个数组 nums 的按位 AND 结果为 0。由于无法将 nums 划分为单个子数组使得元素的按位 AND 结果为 2,因此返回 -1。
提示:
1 <= n == nums.length <= 104
1 <= m == andValues.length <= min(n, 10)
1 <= nums[i] < 105
0 <= andValues[j] < 105

动态规划的位运算

f(i,j) = & = x : i j \Large\And=_{x:i}^j &=x:ij
vNext[cur] 记录符合以下条件之一的next:
一,next-1 < cur。
二,f(i,next) ≠ \neq = f(i,next-1)。
iBitCnt = log(max(nums[i]) ≈ \approx 22 ,显然next的数量不会超过iBitCnt。
如果f(i,j)发生变化,至少一个二进制1变成0。

动态规划

动态规划的状态表示

dp[len][cur] 表示将nums[0…cur]划分为len个区间的最小和。
空间复杂度:O(nm)

动态规划的转移方程

r个区间向r+1个区间转移时:
如果f(cur,next) 等于 andValues[r-1]则:
MinSelf(dp[r+1][x],dp[r][cur-1]+nums[x]) x ∈ [ n e x t , n e x t 的下一个值 ) 这样值设置的时间复杂度是: \in[next,next的下一个值) 这样值设置的时间复杂度是: [next,next的下一个值)这样值设置的时间复杂度是: O ( m × n × i B i t C n t × n ) O(m \times n \times iBitCnt \times n ) O(m×n×iBitCnt×n) ,超时了。
只更新:x = next,其它的用二种方式更新:
如果 (nums[cur]& andValues[r-1]) = andValues[r-1]
则MinSelf(dp[r][cur],dp[r][cur-1])
时间复杂度:$ O ( m × n × i B i t C n t ) O(m \times n \times iBitCnt ) O(m×n×iBitCnt)

动态规划的初始值

枚举第一个区间

动态规范的返回值

dp.back().back()

动态规划的填表顺序

len 从1到m_r-1。
cur从1到m_c-1

代码

核心代码

template<class ELE,class ELE2>
void MinSelf(ELE* seft, const ELE2& other)
{
	*seft = min(*seft,(ELE) other);
}

template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}

class Solution {
public:
	int minimumValueSum(vector<int>& nums, vector<int>& andValues) {
		const int iBitCnt = 22;
		m_r = andValues.size();
		m_c = nums.size();
		const int iMax = (1 << iBitCnt) - 1;
		vector<vector<int>> dp(m_r+1,vector<int>(m_c, m_iNotMay));
		int iAnd = iMax;
		for (int i = 0; i < m_c; i++) {
			iAnd &= nums[i];
			if (iAnd == andValues[0]) {
				dp[1][i] = nums[i];
			}
		}
		vector<set<int>> vNext(m_c);
		{
			vector<int> next(iBitCnt, m_c);
			for (int i = nums.size() - 1; i >= 0; i--) {
				vNext[i] = set<int>(next.begin(), next.end());
				vNext[i].emplace(i);
				vNext[i].erase(m_c);
				for (int bit = 0; bit < iBitCnt; bit++)
				{
					bool b = (1 << bit) & nums[i];
					if (!b) {
						next[bit] = i;
					}
				}
			}
		}
		for (int r = 1; r < m_r; r++)
		{
			for (int cur = 1; cur < m_c; cur++)
			{
				int iAdd = iMax;
				for (const auto& next : vNext[cur]) {
					iAdd &= nums[next];
					if (andValues[r] == iAdd) {
						MinSelf(&dp[r + 1][next], dp[r][cur - 1] + nums[next]);
					}
				}
				if ((andValues[r - 1] & nums[cur]) == andValues[r - 1]) {
					MinSelf(&dp[r][cur], dp[r][cur - 1]+nums[cur]-nums[cur-1]);
				}				
			}			
		}
		{
			int r = m_r;
			for (int cur = 1; cur < m_c; cur++)
			{				
				if ((andValues[r - 1] & nums[cur]) == andValues[r - 1]) {
					MinSelf(&dp[r][cur], dp[r][cur - 1] + nums[cur] - nums[cur - 1]);
				}
			}
		}
		const int iRet = dp.back().back();
		return (iRet >= 1'000'000) ? -1 : iRet;
	}
	int m_r,m_c;
	const int m_iNotMay = 1'000'000'000;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{

	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<int>  nums, andValues;
	int k;

	{
		Solution sln;
		nums = { 1, 9, 8, 8 }, andValues = { 1,8 };
		auto res = sln.minimumValueSum(nums, andValues);
		Assert(9, res);
	}
	{
		Solution sln;
		nums = { 1, 3, 2, 4, 7, 5, 3 }, andValues = { 0, 5, 3 };
		auto res = sln.minimumValueSum(nums, andValues);
		Assert(12, res);
	}
	{
		Solution sln;
		nums = { 1, 4, 3, 3, 2 }, andValues = { 0, 3, 3, 2 };
		auto res = sln.minimumValueSum(nums, andValues);
		Assert(12, res);
	}

	//vector<int>  nums = { 3,6,9 };
	//int k;
	//
	//{
	//	Solution sln;
	//	nums = { 3,6,9 }, k = 3;
	//	auto res = sln.findKthSmallest(nums, k);
	//	Assert(9LL, res);
	//}

}

【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和,# 算法题,动态规划,算法,力扣,c++,区间dp,位运算,最小

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和,# 算法题,动态规划,算法,力扣,c++,区间dp,位运算,最小文章来源地址https://www.toymoban.com/news/detail-852030.html

到了这里,关于【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划系列 | 一文搞定区间DP

    区间 DP 可以用于解决一些涉及到区间合并或分割的问题。区间 DP 通常有以下三个特点: 合并(分割) :将两个或多个部分进行整合,或者反过来将一个区间分解成多个部分。 特征 :能将问题分解为能两两合并的形式。 求解 :对整个问题设最优解,枚举合并点,将问题分

    2024年02月02日
    浏览(35)
  • 石子合并(动态规划 区间DP)+详细注释

    原题链接   活动 - AcWing 题目 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相

    2024年02月16日
    浏览(32)
  • acwing算法基础之动态规划--线性DP和区间DP

    线性DP:状态转移表达式存在明显的线性关系。 区间DP:与顺序有关,状态与区间有关。 题目1 :数字三角形。 解题思路:直接DP即可, f[i][j] 可以来自 f[i-1][j] + a[i][j] 和 f[i-1][j-1] + a[i][j] ,注意 f[i-1][j] 不存在的情况(最后一个点)和 f[i-1][j-1] 不存在的情况(第一个点)。

    2024年02月04日
    浏览(40)
  • 【动态规划】LeetCode 312. 戳气球 --区间DP问题

      Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接       我会一直往里填充内容哒! 🌈LeetCode专栏:专栏链接       目前在刷初级算法的LeetBook 。若每日一题当中有力所能

    2023年04月16日
    浏览(30)
  • 蓝桥杯备赛之动态规划篇——涂色问题(区间DP)

    2023第十四届蓝桥杯模拟赛第二期个人题解(Java实现) 2023第十四届蓝桥杯模拟赛第三期个人题解(Java实现) 蓝桥杯备赛之动态规划篇——背包问题 蓝桥杯真题——单词分析(Java实现) 😘😘 哈喽,大家好!这里是蓝桥杯系列文章的动态规划章节🔥🔥,今天要讲解的是区

    2024年01月23日
    浏览(34)
  • 算法基础复盘笔记Day11【动态规划】—— 区间DP、计数类DP、树形DP、记忆化搜索

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2024年02月01日
    浏览(33)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(35)
  • 【动态规划】【位运算】1787. 使所有区间的异或结果为零

    【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 动态规划汇总 位运算 给你一个整数数组 nums​​​ 和一个整数 k​​​​​ 。区间 [left, right](left = right)的 异或结果 是对下标位于 left 和 right(包括 left 和 right )之间所有元素进行 XOR 运算的结果

    2024年03月17日
    浏览(30)
  • 两个数组的dp问题(2)--动态规划

      一)交错字符串: 97. 交错字符串 - 力扣(LeetCode) 一)确定一个状态标识: 如果我选择s1的一段区间,再进行选择s2得一段区间,那么s3这个字符串的长度就已经固定 预处理:在s1字符串s2字符串和s3字符串前面加上一个虚拟字符,让下标从1开始进行计数 如果要是从1号位置开始进

    2024年02月15日
    浏览(33)
  • 【LeetCode每日一题: 1039. 多边形三角剖分的最低得分 | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】

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

    2023年04月19日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包