leetcode 2172 — 数组的最大与和

leetcode 2172 — 数组的最大与和

一、题目描述

在这里插入图片描述

二、题目分析

题目中给出的篮子数目并不多。然而,如果我们分析在 numSlots = 9,nums.size() = 18 这种情况下可能出现的分配方式个数:第一个篮子有 C 18 2 C_{18}^2 C182 中选择,依此类推,共计 12,504,636,144,000 种情况。因此,我们需要压缩所有情况的个数。

关键点1:每个篮子只能放置2个数字

因此,每个篮子中放置数字的个数只可能是 0,1,2 个。这样共有 3 9 = 19683 3^9 = 19683 39=19683 种可能情况。但是如何计算每种情况下的最大与和呢?

关键点2:在放入数字的总个数确定,放入哪些数字也确定的情况下,最优解与数字的放入顺序无关

对于前述的每种情况,我们都可以得到总共放入的数字个数 count。我们可以认为这 count 个数正好是数组的前 count 个值,且第 count 个数值是最后放入的。

那么,这个问题自然而然就变成了:在每种情况下,将最后放入的数字放在哪个可能的篮子中会得到最优解。不难发现,这是一个动态规划问题。

三、算法

使用状态压缩 + 动态规划:

  1. 如上所述,使用三进制数字表示不同的情况
  2. 动态规划状态方程为: s u m [ n ] = m a x i = 1 & & n 对 应 的 三 进 制 表 示 中 , 第 i 位 不 为 0 n u m S l o t s ( s u m [ n − 3 i ] + n u m s [ 当 前 情 况 下 的 数 字 总 数 − 1 ] & i ) sum[n] = max_{i=1 \&\& n对应的三进制表示中,第 i 位不为0}^{numSlots}(sum[n - 3 ^ i] + nums[当前情况下的数字总数 - 1] \& i) sum[n]=maxi=1&&ni0numSlots(sum[n3i]+nums[1]&i)
    算法总的复杂度为 3 n u m S l o t s ∗ n u m S l o t s 3^{numSlots} * numSlots 3numSlotsnumSlots

四、实现

// 1、列出3的整数次幂
	vector<int> pow3(numSlots);
	int base = 1;
	for (int i = 0; i < numSlots; ++i) {
		pow3[i] = base;
		base *= 3;
	}

	vector<int> maxAndSums(base);
	// 2、遍历所有数字
	for (int i = 0; i < base; ++i) {
		// 2.1 过滤篮子中的数字总数超出 nums.size() 的情况
		int numCount = 0;
		int state = i;
		while (state > 0) {
			numCount += state % 3;
			state /= 3;
		}

		if (numCount > nums.size()) {
			continue;
		}

		// 2.2 状态转移
		state = i;
		int slotCount = 0;
		while (state > 0) {
			if (state % 3 > 0) {
				maxAndSums[i] = max(maxAndSums[i], maxAndSums[i - pow3[slotCount]] + (nums[numCount - 1] & (slotCount + 1)));
			}

			state /= 3;
			++slotCount;
		}
	}

	return *max_element(maxAndSums.begin(), maxAndSums.end());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值