561. Array Partition I

数组配对求和问题
本文探讨了如何从一个包含2n个整数的数组中选取整数对(a1,b1),(a2,b2),...,(an,bn),使得所有对的最小值之和尽可能大。通过排序和哈希表两种方法给出了高效的解决方案。
题目描述:

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:
n is a positive integer, which is in the range of [1, 10000].
All the integers in the array will be in the range of [-10000, 10000].

解题思路

要使得和最大,应该是将数组从小到大进行排序,遍历数组,取第一,第三,第五……小的元素,求和即为结果。如何证明这个结论呢?我们可以假设存在某一种分法得到和最大,此时最大两个元素不是在同一个分组的,而是处于两个不同的部分,那么,将第二大的元素和与最大元素放于一起的元素交换,这两个组的最小值和结果肯定是变大的。因此,最大的两个元素应该是放于同一分组的。依次类推,可以得出结论。

解题代码:

class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        std::sort(nums.begin(), nums.end());
        int sum = 0;
        for (int i = 0; i < nums.size(); i = i + 2) {
            sum += nums[i];
        }
        return sum;
    }
};

上述的解法当然是可行的,但是排序算法的复杂度是没办法到O(n)的,因此可以用下述代码,用空间换时间:

class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        vector<int> hashtable(20001, 0);
        for (size_t i = 0; i<nums.size(); i++)
        {
            hashtable[nums[i] + 10000]++;
        }
        int ret = 0;
        int flag = 0;
        for (size_t i = 0; i<20001;) {
            if ((hashtable[i]>0) && (flag == 0)) {
                ret = ret + i - 10000;
                flag = 1;
                hashtable[i]--;
            }
            else if ((hashtable[i]>0) && (flag == 1)) {
                hashtable[i]--;
                flag = 0;
            }
            else i++;
        }
        return ret;
    }
};
/*
+10000是因为num[i]可能为负值,hashtable元素值为元素下标表示的值的个数。
*/
<think>我们被要求解释NumPy中的`numpy.partition`函数的使用方法及其如何对数组进行操作。根据引用内容,`partition`函数用于对数组进行分区操作,它不会完全排序数组,而是将数组分成两部分:一部分是小于指定位置元素的元素,另一部分是大于或等于该元素的元素,且这两部分内部没有特定顺序。 ### 函数语法 ```python numpy.partition(a, kth, axis=-1, kind='introselect', order=None) ``` 参数说明: - `a`:输入数组 - `kth`:要分区的元素索引(或索引序列),即分区后该索引位置的元素将是排序后该位置的元素,其前面的元素都小于等于它,后面的元素都大于等于它(但整个数组并不完全排序) - `axis`:沿哪个轴进行分区,默认为最后一个轴(-1) - `kind`:选择算法,默认是'introselect',它可以在最坏情况下提供较好的性能 - `order`:当数组是结构化数组时,用于指定字段 ### 核心功能 `np.partition`的工作流程: 1. 选择一个基准索引`kth`(可以是一个整数或整数列表)。 2. 对数组进行部分排序,使得在分区后,索引`kth`处的元素处于其排序后的正确位置。具体来说: - 所有小于该元素的元素被移动到该元素之前(但顺序不定)。 - 所有大于等于该元素的元素被移动到该元素之后(但顺序不定)。 注意:这个操作不会对整个数组进行完全排序,只保证指定位置(kth)的元素处于正确位置,并且其前面的元素都不大于它,后面的元素都不小于它。 ### 示例说明 我们通过一个例子来理解: ```python import numpy as np arr = np.array([3, 2, 6, 4, 1, 5]) print("原始数组:", arr) # [3, 2, 6, 4, 1, 5] # 使用kth=3(即第4小的元素,因为索引从0开始,所以kth=3表示第4个位置) result = np.partition(arr, kth=3) print("分区后的数组:", result) # 可能是 [2, 1, 3, 4, 6, 5] ``` 在这个例子中: - 我们选择`kth=3`,即我们希望分区后索引3(第4个位置)上的元素是原数组排序后第4小的元素(即4)。 - 分区后,索引3的位置是4(确实是第4小的元素)。 - 索引3前面的元素(2,1,3)都小于4,索引3后面的元素(6,5)都大于等于4。但前面和后面的部分都没有排序。 ### 多维数组的分区 当处理多维数组时,我们可以指定`axis`参数。例如,对于一个二维数组,我们可以沿行(axis=0)或列(axis=1)进行分区。 #### 沿行分区(axis=0) ```python arr_2d = np.array([[3, 2, 6], [4, 1, 5], [9, 7, 8]]) print("原始二维数组:\n", arr_2d) # 对每一列进行分区,取kth=1(即每列中第2小的元素放在索引1的位置) result_axis0 = np.partition(arr_2d, kth=1, axis=0) print("沿axis=0分区(每列):\n", result_axis0) ``` 输出可能为: ``` 原始二维数组: [[3 2 6] [4 1 5] [9 7 8]] 沿axis=0分区(每列): [[3 1 5] [4 2 6] [9 7 8]] ``` 解释:沿列方向(axis=0)分区,每列独立进行分区。以第一列为例:元素为[3,4,9],排序后为[3,4,9],当kth=1时,索引1位置应该是4(第二小的元素)。分区后第一列变为[3,4,9](因为3<4,9>4,符合要求)。 #### 沿列分区(axis=1) ```python # 对每一行进行分区,取kth=1(即每行中第2小的元素放在索引1的位置) result_axis1 = np.partition(arr_2d, kth=1, axis=1) print("沿axis=1分区(每行):\n", result_axis1) ``` 输出可能为: ``` 沿axis=1分区(每行): [[2 3 6] [1 4 5] [7 8 9]] ``` 解释:沿行方向(axis=1)分区,每行独立进行分区。以第一行为例:元素为[3,2,6],排序后为[2,3,6],当kth=1时,索引1位置应该是3(第二小的元素)。分区后第一行变为[2,3,6](因为2<3,6>3,符合要求)。 ### 同时指定多个kth `kth`参数也可以是一个列表,表示多个分区位置。例如,`kth=[1,2]`表示同时保证索引1和索引2位置上的元素是排序后该位置应有的元素。 ```python arr = np.array([10, 1, 9, 8, 4, 7]) result = np.partition(arr, kth=[1, 3]) print("多kth分区:", result) # 可能输出 [1, 4, 7, 8, 9, 10] ``` 解释:分区后,索引1位置是4(第二小的元素),索引3位置是8(第四小的元素)。同时,索引1之前的元素(1)小于4,索引1和3之间的元素(7)在4和8之间,索引3之后的元素(9,10)大于8。 ### 性能与应用 - `np.partition`的时间复杂度是$O(n)$,而完全排序是$O(n\log n)$,因此当只需要部分排序时,它比完全排序更高效[^1]。 - 应用场景:快速找到第k小的元素,或者获取最小的k个元素(此时分区后前k个元素就是最小的k个元素,但未排序)。 ### 与排序的区别 - `np.sort`:完全排序,整个数组有序。 - `np.partition`:部分排序,只保证指定位置上的元素正确,其他元素只保证在正确的分区。 ### 总结 `numpy.partition`函数提供了一种高效的部分排序方法,特别适用于需要快速获取第k小元素或最小/最大的k个元素的场景。理解其分区原理有助于在需要部分排序时合理使用。 §§相关问题§§ 1. 如何利用`np.partition`获取数组中最小的k个元素? 2. `np.partition`和`np.argpartition`有什么区别? 3. 在多维数组中使用`np.partition`时,如何指定不同的轴? 4. `np.partition`的时间复杂度是多少?为什么比完全排序快?</think>### NumPy `partition` 函数详解 `numpy.partition()` 是 NumPy 中用于高效部分排序的核心函数,它能将数组元素按指定位置分区,但不完全排序整个数组。以下是详细使用方法: #### 1. **基本语法** ```python numpy.partition(a, kth, axis=-1, kind='introselect', order=None) ``` - `a`:输入数组 - `kth`:分区基准位置(索引或索引列表) - `axis`:操作轴(默认为最后一个轴) - `kind`:选择算法(默认'introselect',高效处理大型数组) #### 2. **核心功能** - **分区原理**:以 `kth` 位置的元素为基准,将数组分成两部分: - 左侧:所有小于基准值的元素(无序) - 右侧:所有大于等于基准值的元素(无序) - **不进行完全排序**,只保证基准元素在正确位置[^2][^4] #### 3. **使用示例** ##### 一维数组分区 ```python import numpy as np arr = np.array([10, 5, 8, 4, 7, 2, 9]) partitioned = np.partition(arr, kth=3) # 以索引3为基准分区 print(partitioned) # 输出示例: [ 2 4 5 7 8 10 9] ``` - 基准元素 `7` 位于索引3 - 左侧元素 `[2,4,5] < 7` - 右侧元素 `[8,10,9] ≥ 7` ##### 二维数组分区(沿指定轴) ```python arr_2d = np.array([[9, 2, 5], [7, 1, 8], [4, 6, 3]]) # 沿列方向分区(axis=0) col_part = np.partition(arr_2d, kth=1, axis=0) """ 输出示例: [[4 1 3] [7 2 5] [9 6 8]] 每列索引1位置的元素已固定: 第0列: 索引1=7 (排序后位置正确) 第1列: 索引1=2 第2列: 索引1=5 """ # 沿行方向分区(axis=1) row_part = np.partition(arr_2d, kth=1, axis=1) """ 输出示例: [[2 5 9] [1 7 8] [3 4 6]] 每行索引1位置的元素已固定 """ ``` #### 4. **关键特性** 1. **高效性**:时间复杂度 $O(n)$,比完全排序 $O(n \log n)$ 更快[^1] 2. **多基准支持**:可指定多个基准位置 ```python multi_kth = np.partition([10, 5, 8, 4, 7], kth=[1, 3]) # 输出: [ 4 5 7 8 10] # 索引1=5, 索引3=8 位置固定 ``` 3. **应用场景**: - 快速获取前k小/大元素 - 数据预处理(如机器学习特征选择) - 替代完全排序提升性能 #### 5. **与排序的区别** | 操作 | 结果 | 时间复杂度 | |------------------|----------------------|------------| | `np.sort()` | 完全排序 | $O(n \log n)$ | | `np.partition()` | 仅保证基准位置正确 | $O(n)$ | > 当只需获取第k小的元素或部分有序数据时,`partition()` 比完全排序高效10倍以上[^1][^3] ### 总结 `numpy.partition()` 通过部分排序实现高效数据分区: 1. 以 `kth` 索引元素为基准划分数组 2. 左侧元素 ≤ 基准值,右侧元素 ≥ 基准值 3. 分区内元素无序,仅保证基准位置正确 4. 特别适合大数据集的部分排序需求
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值