[LeetCode] 561. Array Partition I

Description

Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.

Example 1:

Input: [1,4,3,2]

Output: 4
Explanation: n is 2, and the maximum sum of pairs is 4 = min(1, 2) + min(3, 4).

Note:

  1. n is a positive integer, which is in the range of [1, 10000].
  2. All the integers in the array will be in the range of [-10000, 10000].

Analyse

将输入的序列分为两部分,a和b

最大化 \(\sum_i min(a_i, b_i)\)

取序列里一半的数,比另一半小,最大的数不能取,于是取第二大的,第三大的不能取,取第四大的,以此类推就能得到这个分组

先将nums排序,然后取第0,2,4,6,...,2n个元素,加起来就是最大的\(\sum_i min(a_i, b_i)\)

时间复杂度
sort排序,没有研究过代码实现,据各种博客说是多种排序算法的混合,时间复杂度可以算成 \(O(nlogn)\)

整个函数的时间复杂度 \(O(nlogn)\)

空间复杂度 \(O(n)\)

int arrayPairSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());

    int sum = 0;

    for(int i = 0; i < nums.size(); i+=2)
    {
        sum += nums[i];
    }

    return sum;
}

看了下LeetCode上用时最短的版本,可以看到这位大佬的第一个版本和我的思路一样,但注释了然后写出了一个更快的版本

int arrayPairSum(vector<int>& nums) {
    // 1, 2, 3, 11
    // sort(nums.begin(), nums.end());
    // int s = 0;
    // for (int i = 0; i < nums.size(); i += 2)
    //     s += nums[i];
    // return s;

    int f[20001] = {};
    for (int i = 0; i < nums.size(); ++i) ++f[10000 + nums[i]]; 

    int sum = 0;
    int c = 0;
    for (int i = 0; c < nums.size() - 1; ++i) {
        int k = (f[i] + 1 - (c & 0x01)) >> 1;
        sum += (i - 10000)*k;
        c += f[i];
    }

    return sum;
}

不太明白,举个例子看看效果 nums = {1,2,3,11}

int f[20001] = {};
for (int i = 0; i < nums.size(); ++i) ++f[10000 + nums[i]];

f的长度为20001是因为nums中元素的取值范围是[-10000, 10000]

f的后10000位存储nums中各个元素出现的次数

f[10001] = 1
f[10002] = 1
f[10003] = 1
f[10011] = 1

int sum = 0;
int c = 0;
for (int i = 0; c < nums.size() - 1; ++i) {
    int k = (f[i] + 1 - (c & 0x01)) >> 1;
    sum += (i - 10000)*k;
    c += f[i];
}

这个例子{1,2,3,11}中都是正数,直接从f[10000]开始看,之前的循环都是0

i k sum c
9999 (f[9999]+1 - (0 & 0x01)) >> 1=0 sum=sum+(9999-10000) * 0=0 c= c+f[9999]=0
10000 (f[10000]+1 - (0 & 0x01)) >> 1=0 sum=sum+(10000-10000) * 0=0 c= c+f[10000]=0
10001 (f[10001]+1 - (0 & 0x01)) >> 1=1 sum=sum+(10001-10000) * 1=1 c= c+f[10001]=1
10002 (f[10002]+1 - (1 & 0x01)) >> 1=0 sum=sum+(10002-10000) * 0=1 c= c+f[10002]=2
10003 (f[10003]+1 - (2 & 0x01)) >> 1=1 sum=sum+(10003-10000) * 1=4 c= c+f[10003]=3

到这里c的值为3,退出循环,输出sum = 4

我终于看明白了,和我写的一个意思

注意到在i为1,2,3的时候k为1,0,1,乘起来求和就是sumc用来记录已经检测的nums里的值的个数, c < nums.size() - 1时就可以结束了,最后一个值不用看,最后返回sum

Reference

  1. http://www.cplusplus.com/reference/algorithm/sort/
posted @ 2019-01-21 16:13  arcsinW  阅读(138)  评论(0编辑  收藏  举报