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;
}