LeetCode-问题2611-老鼠和奶酪

题目链接

https://leetcode.cn/problems/mice-and-cheese/

解答过程

这个题目乍一看不太好理解,但仔细分析题目要求并不复杂。翻译一下,给定两个等长的数组,现在从数组1的k个位置挑k个元素,从数组2挑其余位置的n-k个元素,期望的是挑出来的元素之和最大,求这个最大和是多少。

对于这种求最值的问题,题目难度设定是中等,我就倾向从动态规划的角度入手。但是,想不出合适的动态规划方程。

那就还是用基于示例的归纳法,尝试从示例问题中寻找解题思路。以示例问题为例,数组1是{1,1,3,3},数组2是{4,4,1,1},现在要从数组1中挑2个元素,从数组2中挑其余2个元素,怎么挑能使得挑出来的元素之和最大呢?要不要挑数组1的第1个元素,显然不要,因为数组1的第1个元素是1,数组2的第1个元素是4,如果希望和最大,那么应当尽量倾向数组2的第1个元素被挑出来。同理,数组1的第2个元素也不应该被挑出来。而数组1的第3个和第4个元素应当被挑出来。换句话说,我们应当尽量挑同位置上,数组1比数组2大的那些。如何得到哪些位置上数组1比数组2大呢?我们可以维护一个diff数组,diff每个元素是同位置上数组1和数组2的差值。当我们挑选第1个位置时,我们应当挑diff数组中元素值最大的那个位置。当我们挑选第2个位置时,我们应当挑diff数组中元素值第二大的那个位置。以此类推,题目可解。

	public int miceAndCheese(int[] reward1, int[] reward2, int k) {
		int n = reward1.length;

		int maxCheese;
		if (k <= n/2) {
			maxCheese = maxCheese(reward1, reward2, k);
		} else {
			maxCheese = maxCheese(reward2, reward1, n-k);
		}

		return maxCheese;
	}

	private int maxCheese(int[] reward1, int[] reward2, int k) {
		int n = reward1.length;

		int[] diff = new int[n];
		for (int i = 0; i < n; i++) {
			diff[i] = reward1[i] - reward2[i];
		}

		boolean[] used = new boolean[n];

		for (int i = 0; i < k; i++) {
			int maxDiffIdx = maxDiffIdx(diff);
			used[maxDiffIdx] = true;
			diff[maxDiffIdx] = Integer.MIN_VALUE;
		}

		int maxCheese = 0;
		for (int i = 0; i < n; i++) {
			if (used[i]) {
				maxCheese += reward1[i];
			} else {
				maxCheese += reward2[i];
			}
		}

		return maxCheese;
	}

	private int maxDiffIdx(int[] diff) {
		int maxDiffIdx = 0;
		int maxDiff = diff[0];
		for (int i = 0; i < diff.length; i++) {
			if (diff[i] > maxDiff) {
				maxDiff = diff[i];
				maxDiffIdx = i;
			}
		}

		return maxDiffIdx;
	}

代码里每次挑选要遍历diff数组,挑选完置diff数组对应位置为无效值,并且还需要一个布尔数组标识哪些位置被挑除选出来了。为了减少遍历的次数,我还增加了一次如有必要的swap。代码提交以后是可以通过的,不过效率很差。

看了一下官方题解,整体思路还是比较相像的,但是在求元素和的地方有较大不同。细思一下,恍然大悟,确实我的多次循环笨拙而低效了。对于挑选出来的某个位置i,我们的目标是用arr1[i]来做加和,arr1[i] = arr1[i] + arr2[i] - arr2[i] = arr2[i] + arr1[i] - arr2[i] = arr2[i] + diff[i]。因此,只需要将数组2的所有元素之和加上diff数组最大的k个元素即可。如果只需要diff数组最大的k个元素,而不需要感知具体位置,那么直接对diff数组做排序就可以了。

	public int miceAndCheese(int[] reward1, int[] reward2, int k) {
		int n = reward1.length;

		int[] diff = new int[n];
		for (int i = 0; i < n; i++) {
			diff[i] = reward1[i] - reward2[i];
		}

		Arrays.sort(diff);

		int maxCheese = 0;
		for (int i = 0; i < n; i++) {
			maxCheese += reward2[i];
		}

		for (int i = 0; i < k; i++) {
			maxCheese += diff[n-1-i];
		}

		return maxCheese;
	}

代码提交以后,效率果然好了很多,代码也简洁了很多。

最后多想一下,我上面的较笨拙的解法在某些场景下也有可取之处,比如,题目要求不止计算最大和,还要计算出具体位置。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值