力扣刷题总结 -- 数组20

58. 最后一块石头的重量(简单)

题目要求:

将所有石头的重量放入最大堆中。每次依次从队列中取出最重的两块石头 a 和 b,必有 a≥b。如果 a>b,则将新石头 a−b 放回到最大堆中;如果 a=b ,两块石头完全被粉碎,因此不会产生新的石头。重复上述操作,直到剩下的石头少于2块。

最终可能剩下1块石头,该石头的重量即为最大堆中剩下的元素,返回该元素;也可能没有石头剩下,此时最大堆为空,返回0。

题目分析:

每次取最大的两块石头进行粉碎,有剩余就放回,直到最终所有石头被粉碎或剩余一块。

题目解答:

#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>


class Solution
{
public:
	vector<int> addToArrayForm(vector<int>& num, int k)
	{
		vector<int> res;
		int n = num.size();

		for (int i = n - 1; i >= 0; i--)  // 从个位开始遍历数组
		{
			int sum = num[i] + k % 10;  // 将数组的元素和k中相应的位置相加
			k /= 10;  // 将k除以10,便于取出k的下一位元素

			if (sum >= 10)  // 如果本位元素大于10,下一位元素+1
			{
				k++;
				sum -= 10;
			}
			res.push_back(sum);
		}

		for (; k > 0; k /= 10)  // 如果相加后元素超出原来元素的位数,再增加一位
		{
			res.push_back(k % 10);
		}

		reverse(res.begin(), res.end());  // res中的元素从个位开始排序,需要翻转
		return res;
	}

};


int main()
{
	vector<int> nums = { 2,7,4 };
	int k = 181;
	Solution s;

	cout << "原数组为:";
	for (auto & num : nums)
	{
		cout << num << ", ";
	}
	cout << endl;

	cout << "待加数为:" << k << endl;

	vector<int>res = s.addToArrayForm(nums, k);

	cout << "相加后数组为:";
	for (auto & num : res)
	{
		cout << num << ", ";
	}
	cout << endl;

	system("pause");
	return 0;
}

59. K 次取反后最大化的数组和(简单)

题目要求:

给定一个整数数组nums和一个整数k,按以下方法修改该数组:

选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。
重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组可能的最大和

题目分析:

根据题意,数组中有负数时优先对负数取反,将所有负数取反后如果k>0,判断k是奇数还是偶数,若是偶数,求和结果不变;若是奇数,之前的求和结果减去2倍数组中的最小数。

题目解答:

#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>


class Solution
{
public:
	int largestSumAfterKNegations(vector<int>& nums, int k)
	{
		sort(nums.begin(), nums.end());  // 对数组进行升序排序
		int sum = 0;

		// 优先将数组中的负数取反
		for (int i = 0; i < nums.size(); i++)
		{
			if (nums[i] < 0 && k > 0)
			{
				nums[i] = -1 * nums[i];
				k--;
			}

			sum += nums[i];
		}

		sort(nums.begin(), nums.end());

		// 将所有负数取反后,如果k还有余,k为偶数则不做任何变化;k为奇数则之前的求和结果减去2倍数组中的最小数
		return sum - (k % 2 == 0 ? 0 : 2 * nums[0]);
	}

};


int main()
{
	vector<int> nums = { 3,-1,0,2 };
	int k = 3;
	Solution s;

	int res = s.largestSumAfterKNegations(nums, k);

	cout << "取反后求和为:" << res << endl;

	system("pause");
	return 0;
}

60. 将数组分成和相等的三个部分(简单)

题目要求:

给定一个整数数组 arr,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。

形式上,如果可以找出索引 i + 1 < j 且满足 (arr[0] + arr[1] + … + arr[i] == arr[i + 1] + arr[i + 2] + … + arr[j - 1] == arr[j] + arr[j + 1] + … + arr[arr.length - 1]) 就可以将数组三等分。

题目分析:

假设数组有n个元素,元素之和为s,如果arr[0] + arr[1] + … + arr[i] = s / 3,且arr[0] + arr[1] + … + arr[i] + arr[i + 1] + arr[i + 2] + … +arr[j] = (s / 3) * 2,且j + 1 < n,则该数组满足题意。

题目解答:

#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>


class Solution
{
public:
	bool canThreePartsEqualSum(vector<int>& arr)
	{
		int s = accumulate(arr.begin(), arr.end(), 0);  // 获取数组元素之和

		if (s % 3 != 0)  // 判断数组能否被3整除
		{
			return false;
		}

		int target = s / 3;
		int n = arr.size(), i = 0, cur = 0;

		while (i < n)
		{
			cur += arr[i];  // 从头开始累计求和
			if (cur == target)  // 求和结果等于target就跳出循环
			{
				break;
			}
			i++;
		}

		if (cur != target)  // 如果求和结果始终不等于target,说明无法满足题意
		{
			return false;
		}

		int j = i + 1;
		while (j + 1 < n)  // 确保最后一个子数组不为空
		{
			cur += arr[j];
			if (cur == target * 2)
			{
				return true;
			}
			j++;
		}

		return false;
	}

};


int main()
{
	vector<int> nums = { 0,2,1,-6,6,-7,9,1,2,0,1 };
	Solution s;

	bool res = s.canThreePartsEqualSum(nums);

	if (res == true)
	{
		cout << "该数组可以分成和相等的三个部分!" << endl;
	}
	else
	{
		cout << "该数组不可以分成和相等的三个部分!" << endl;
	}

	system("pause");
	return 0;
}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值