Description
对于一个整数数列A[0], A[1], …, A[N-1]进行分组,要求每组1到2个数,并且同组之和不能大于w. 求最少可以分成多少组.
1 <= N <= 100000, 1 <= A[i] <= w <= 1000000000.
请实现下面Solution类中计算minPartition(A, w)的函数.
class Solution {
public:
int minPartition(vector<int> A, int w) {
}
};
例1:当A = {2, 5, 4, 3}, w = 5, minPartition(A, w)返回3. 将2和3放一组,4和5各自单独作为一组,共3组.
例2:当A = {2, 5, 4, 3}, w = 7, minPartition(A, w)返回2. 将2和5放一组,3和4一组,共2组.
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
解析:
当时没想出来,一直想啥动态规划。之后和室友交流下,其实思路很简单。自己居然把排序等一般的方法都忘了,思维太局限了。leetcode要认真打了啊。。。
把A从小至大排序。找到能和最小的数字匹配的最大的数字的下标,这些数字一一配对,处理一下,即可得最大的对数。然鹅我的思路还是WA,参考了别人的代码才发现自己的疏漏。第一个函数是我的错误代码,第二个是正确的。
正确思路举例:w = 8,序列为2 4 5 6 7
先把数组从小到大排序,尽可能多划分组,就要求小的和尽量大的一组。
head指针从头取剩余最小的,tail指针从尾部找能和head相加后小于w的最大值。tail每轮循环都要向向前移动一位,即tail–,同时res++,因为tail所指向的数字必须单独列为一组。如果tail所值的数字和head所指的数字相加满足要求,则head++,tail–,res++(因为得到一组)。最终假设还剩下两个数,head指向第一个,tail指向第二个数。① 二者相加符合条件,则head++,tail–并且res++。不满足head < tail,结束。②二者相加不符合条件,则tail–,res++,进入下一轮循环此时head == tail,不符合head < tail,所以结束。但是head 和tail所指的数字仍自成一组,故res++。
代码:
class Solution {
public:
/*这个方法一直令head = 0
*是错误的,如2 4 5 6 7, w = 8,
*当tail到6的时候,2 + 6 <= 8没错
*但是4 + 5 = 9,中间的就不一定符合要求
*/
int minPartitionWrong(vector<int> A, int w) {
sort(A.begin(), A.end()); // 从小至大排序
int pairsNum = 0;
int doublePairsNum;
int size = A.size();
for (doublePairsNum = size - 1; doublePairsNum >= 0; doublePairsNum--) {
int sum = A[doublePairsNum] + A[0]; // 找到符合条件的最大的数下标
if (sum <= w) break;
}
pairsNum = (doublePairsNum + 1) / 2;
return size - pairsNum;
}
正确的解答:
int minPartition(vector<int> A, int w) {
sort(A.begin(), A.end()); // 从小至大排序
int tail, head = 0, res = 0;
int size = A.size();
for (tail = size - 1; tail >= 0 && head < tail; tail--) {
if (A[tail] + A[head] <= w) {
head++;
}
res++;
}
if (tail == head)
res++;
return res;
}
};