代码随想录算法训练营Day33 | 1005.K 次取反后最大化的数组和、134.加油站、135.分发糖果

1005.K 次取反后最大化的数组和

思路好简单,但写起来一直出错,难受啊

思路:

先对数组排个序,先对所有负数取反,得到一个全是正数的数组

对于这个全是正数的数组,对数组中绝对值最小的那个元素取反即可

由于排序是直接默认升序排列而非按照绝对值排序,写获取绝对值最小元素时细节还挺多的 

int largestSumAfterKNegations(vector<int>& nums, int k) {
	std::sort(nums.begin(), nums.end());

	// 先将所有负数取反
	int i = 0;
	for (; i < nums.size() && k > 0; ++i, --k) {
		if (nums[i] < 0)
			nums[i] *= -1;
		else
			break;
	}

	// 正数中只需要对最小的那个取反
	if (k % 2 == 1) {
		// 1、原数组中全是负数,都取反后k还没消耗完,对最后一个元素取反
		if (i == nums.size())
			nums[i - 1] *= -1;
		// 2、原数组中全是正数,对第一个元素取反
		// 3、原数组中有正有负,对绝对值最小的一个取反(i-1是原先绝对值最小的负数,i是原先绝对值最小的正数)
		else if(i == 0 || nums[i] < nums[i - 1])
			nums[i] *= -1;
		else
			nums[i - 1] *= -1;
	}

	int ans = 0;
	for (int n : nums)
		ans += n;

	return ans;
}

134.加油站

这题的重点是抓住每个加油站的净加油量

思路:寻找一个加油站,该加油站前所有加油站的净加油量最小,从此处出发能实现“硬骨头放在最后啃”的效果

只改变出发站点的情况下,全程的净加油量是固定的。那么就能得出:如果一个站点之前的总净加油量越小,那么该站点之后的总净加油量就越大。

int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
	int sum = 0;
	int ans = 0;
	int minSum = sum;
	// 计算全程的净加油量
	for (int i = 0; i < gas.size(); ++i) {
		sum += gas[i] - cost[i];
		if (sum < minSum) {
			ans = i + 1;
			minSum = sum;
		}
	}
	// 全程净加油量总和小于0说明一定跑不完全程
	if (sum < 0)
		return -1;
	else
		return ans;
}

135.分发糖果

想了半天好像能写出来但又死活写不出来 :(

正常按逻辑写有两个问题始终解决不了:

1、相邻评分不同时,差值不一定是1,如何确定到底差多少?

2、相邻评分相同时,更难判断,任意值都可以作为差值,得根据再相邻的情况进一步判断。

解析中把一个相邻问题拆成了与左比和与右比两个问题,分别解决再进行合并

本题的局部最优:一个小孩的糖果数和左边比符合条件,和右边比也符合条件

推导出的全局最优:所有小孩的糖果与左右比都符合条件

思路:分别处理与左边比的结果和与右边比的结果,再对两边的结果进行合并

第一步:从前往后逐个获取与左对比的结果,如果评分比左边高,则糖果量比左多1,评分低则糖果量不变
第二步:从后往前逐个获取与右对比的结果,如果评分比右边高,则糖果量比右多1,评分低则糖果量不变
第三步:左右的结果中取糖果量较大的一个(兼容两个结果)

int candy(vector<int>& ratings) {
	// 初始所有人都是一个糖果
	vector<int> candy(ratings.size(), 1);

	// 先从前往后逐个获取与左对比的结果
	for (int i = 1; i < ratings.size(); ++i) {
		// 如果比左大,糖果数就变为比左边多一个
		if (ratings[i] > ratings[i - 1])
			candy[i] = candy[i - 1] + 1;
	}
	// 从后向前逐个获取与右对比的结果,糖果量取较大值
	for (int i = ratings.size() - 2; i >= 0; --i) {
		// 将二三步简写在一起
		if (ratings[i] > ratings[i + 1])
			candy[i] = std::max(candy[i + 1] + 1, candy[i]);
	}

	int ans = 0;
	for (int n : candy)
		ans += n;
	return ans;
}
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值