408数据结构算法题专项-2016

题目:

基础:我写完了代码被 1 2 3 3 5这组数据钻牛角了。发现自己搞错了一些基础概念。首先,集合具有唯一性,不存在相同的元素,所以这组数据不可能存在。其次,不相交三个字并不是没意义,因为子集有很多个,不相交三个字把子集的划分方式规定死了,就是把两个子集拼装能变回原集合。

分析:相比于前几年的线性表算法题难度有明显提升。不再能直接暴力思路模拟题干。①不相交即没有公共元素,规定了子集划分方式。②|n1-n2|最小即两个子集分配的时候要尽量雨露均沾。③|S1-S2|最大即,虽然分配元素个数要差不多,但分配出去的元素大小相差很大,联想到一种思路即分一个大的出去,然后分一个小的出去,前提是存在一条有序的序列能让我们这么做。从而得到一种可能可行的思路即排序后分果果,理论推完实践开始。

(打脸了,之前2013的想偷懒不写排序的优化代码,现在直接变成首选了。。。。。,不过还是偷了一下懒,没写归并的模板,调用了sort函数)

思路一:sort排序(快排+插排)

 #include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5;
int A[N],A1[N],A2[N];
int n1,n2,S1,S2,n;
void check(int A[],int n)
{
	for(int i=0,j=n-1;i<=j;i++,j--)//依次分配
	{
		if(i!=j)
		{
			A1[n1++]=A[i];
			S1+=A[i];
			A2[n2++]=A[j];
			S2+=A[j];
		}
		else//当元素为奇数个时,决定中间那个元素的去留
		{
			if(S1<S2) A2[n2++]=A[i],S2+=A[i];
			else A1[n1++]=A[i],S1+=A[i];	
		} 
	}
	for(int i=0;i<n1;i++) cout<<A1[i]<<' ';
	puts("");
	for(int i=0;i<n2;i++) cout<<A2[i]<<' ';
	puts("");
	printf("|n1-n2|=%d,|S1-S2|=%d",abs(n1-n2),abs(S1-S2));
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) cin>>A[i];
	sort(A,A+n);//快速+插入排序
	check(A,n);//分配集合
	return 0;
}

平均时间复杂度为:O(nlongn),最坏时间复杂度为:O(n^2)但是在该题目情景下不会进入到最坏情况。空间复杂度为:O(logn)

思路二:归并排序

思考:想进一步在排序的思路上降低时间复杂度,就得实现真正O(nlogn)的算法即归并排序。

具体模板请自行搜索,推荐Acwing y总写的归并模板。

思路三:调整排序

思考:再再一次提升效率只能针对排序的内部实现优化,具体想了解参考2016年专业408算法题,或看王道的真题讲解(个人感觉这次的讲解的不是很形象,可能是上来就是最优解的原因,必须熟悉和理解快排原理的基础上才能改动模板)。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘟嘟嘟11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值