假设n为偶数,现在要求将n个数分成两个等规模的集合s1,s2,并且使得s1中元素的和减去s2中元素之和的差是最大值。请写算法,并分析时间性能。
看到这个题目,直观理解,我想到了直接把这个数组中的数字进行排序,元素之和的差最大,也当然就是排序过后的前一半和后一半元素差值最大,显然,一个快速排序可以满足这个要求。快排的时间复杂度为O(nlgn)
考虑到分治思想,该如何进行优化。例如二分搜索的基本思想是,将n个元素分成两个等规模的集合s1,s2,取a[n/2]与x相比较。如果x=a[n/2],则找到x,终止算法;如果x=a[n/2],则在数组a的左半部分继续搜索x;如果x=a[n/2],则在右边寻找。在最坏情况下,while循环被执行了O(logn)次。循环体内运算需要O(1)时间,因此整个算法在最坏情况下的时间复杂性为O(logn)。
利用快速排序的划分思想,设正整数集合为数组S,划分为前半个数组S1,后半个数组为S2,若第一次划分的轴值是中位数,则返回;若不是继续划分中位数所在的部分。
考虑快排中的分治思想
如果s1 (大的数集)的的个数大于n/2
将(i<=n/2-loW-1)个最小的数排到后面
如果s1 (大的数集)的的个数小于n/2
将s2 (小的数集) n/2-low-1排到前面
将排好的数组的前n/2个数赋值给s1
将排好的数组的后n/2个数赋值给s2
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace std;
const int n = 8;
void partions(int a[], int low, int high)
{ //进行一趟快排
int key = a[low];
a[0] = a[low];
while (low < high)
{
while (low < high && a[high] <= key)
{
--low;
a[low] = a[high];
}
while (low < high && a[low] >= key)
{
++low;
a[high] = a[low];
}
}
a[low] = key;
//如果s1(大的数集)的的个数大于n/2
if (low >= n / 2)
{
for (int i = 0; i <= n / 2 - low - 1; ++i)
{
for (int j = 0; j < n - 1; ++j)
{
if (a[j] < a[j + 1])
{
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
//如果s1(大的数集)的的个数小于n/2 else
else
{
for (int i = 0; i <= n / 2 - low - 1; ++i)
{
for (int k = n - 1; k < n - i; ++k)
{
if (a[k] > a[k - 1])
{
int temp1 = a[k];
a[k] = a[k - 1];
a[k - 1] = temp1;
}
}
}
}
}
int main()
{
int a[n] = {1, 3, 5, 9, 6, 0, -11, -8};
partions(a, 0, n - 1);
for (int i = 0; i < n; ++i)
{
if (i < 4)
{
cout << "属于子集s1的" << endl;
cout << "属于子集s2的" << endl;
cout << a[i] << endl;
}
}
return 0;
}
时间复杂度O(n),空间复杂度O(1)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现