1603. 整数集合划分(2016年408数据结构算法题)

一、题目

1603. 整数集合划分icon-default.png?t=N7T8https://www.acwing.com/problem/content/description/1605/1603. 整数集合划分(2016年408数据结构算法题)_第1张图片

1603. 整数集合划分(2016年408数据结构算法题)_第2张图片

二、算法的基本设计思想

由题意知,将最小的 \left \lfloor \frac{n}{2} \right \rfloor 个元素放在 A_{1} 中,其余的元素放在 A_{2} 中,分组结果即可满足题目要求。仿照快速排序的思想,基于枢轴将 n 个整数划分为两个子集。根据划分后枢轴所处的位置i分别处理:

① 若 i = \left \lfloor \frac{n}{2} \right \rfloor,则分组完成,算法结束;

② 若 i < \left \lfloor \frac{n}{2} \right \rfloor,则枢轴及之前的元素均属于 A_{1} ,继续对 i 之后的元素进行划分;

③ 若 i > \left \lfloor \frac{n}{2} \right \rfloor,则枢轴及之后的元素均属于 A_{2} ,继续对 i 之前的元素进行划分;

基于该设计思想实现的算法,无须对全部元素进行全排序,其平均时间复杂度是O(n),空间复杂度是O(1)

三、算法实现

#include 
#include 
using namespace std;

int setPartition(int a[], int n) {
    int pivotkey, low = 0, low0 = 0, high = n - 1, high0 = n - 1, flag = 1, k = n / 2, i; //pivotkey保存枢轴元素值
    //low0,high0保存low,high的初值,避免丢失进行后续多轮的划分的位置定位
    int s1 = 0, s2 = 0; //记录A1、A2集合各自的和
    while(flag) {
        pivotkey = a[low]; //选择枢轴
        while(low < high) { //基于枢轴对数据进行划分
            while(low < high && a[high] >= pivotkey) --high; //若数组最右边的值比枢轴的值大,说明不需要调整,往左移动high继续比较即可
            if(low != high) a[low] = a[high]; //找到第一个比枢轴元素值小的元素,将其调整到前面
            while(low < high && a[low] <= pivotkey) ++low; //若数组最左边的值比枢轴的值小,说明不需要调整,往右移动low继续比较即可
            if(low != high) a[high] = a[low]; //找到第一个比枢轴元素值大的元素,将其调整到后面
        } //end of while(low < high)
        a[low] = pivotkey; //最后将枢轴放到两堆元素的中间
        if(low == k - 1) //如果枢轴是第n/2小元素,划分成功
            flag = 0;
        else{ //否则继续划分
            if(low < k - 1) { //枢轴及之前的元素均属于A1,继续对 low 之后的元素进行划分;
                low0 = ++low;
                high = high0;
            }
            else{ //否则枢轴及之后的元素均属于A2,继续对 low 之前的元素进行划分;
                high0 = --high;
                low = low0;
            }
        }
    }
    for(i = 0; i < k; i++) s1 += a[i]; //计算S1和
    for(i = k; i < n; i++) s2 += a[i]; //计算S2
    printf("%d %d", (n-k)-k, s2-s1);
    return s2-s1;
}


int main() {
    int n;
    cin>>n;
    int a[n];
    for(int i = 0;i < n; i++)
        cin>>a[i];
    setPartition(a,n);
}

四、关于快速排序

快速排序是一种常见且高效的排序算法,它基于分治的思想。它的基本思想是选择一个基准元素,然后将数组分为两个子数组,一个子数组中的元素都小于基准元素,另一个子数组中的元素都大于基准元素。然后对这两个子数组分别递归地进行快速排序,直到整个数组有序。

具体来说,快速排序的过程如下:

  1. 选择一个基准元素,通常是数组中的第一个元素。
  2. 将数组中小于基准元素的元素移到基准元素的左边,大于基准元素的元素移到基准元素的右边,基准元素放在中间。
  3. 递归地对基准元素左右两边的子数组进行快速排序。

你可能感兴趣的:(刷题,算法,数据结构)