目录
题目
作者: Turbo时间限制: 1S章节: 课程设计
问题描述 :
给你一个整数数组 nums 和一个整数 k 。你需要找到 nums 中长度为 k 的子序列 ,且这个子序列的 和 最大 。
请你返回 任意 一个长度为 k 的整数子序列。
子序列 定义为从一个数组里删除一些元素后,不改变剩下元素的顺序得到的数组。
示例 1:
输入:
4
2 1 3 3
2
输出:
3 3
解释:
子序列有最大和:3 + 3 = 6 。
示例 2:
输入:
4
-1 -2 3 4
3
输出:
-1 3 4
解释:
子序列有最大和:-1 + 3 + 4 = 6 。
示例 3:
输入:
4
3 4 3 3
2
输出:
3 4
解释:
子序列有最大和:3 + 4 = 7 。
另一个可行的子序列为 [4, 3] 。
输入说明 :
输入三行:
第一行为一个整数n代表数组nums的长度。
第二行输入n个整数代表数组nums的元素。
第三行为一个整数k。
提示:
1 <= n <= 1000
-10^5 <= nums[i] <= 10^5
1 <= k <= n
输出说明 :
输出一行k个整数表示结果,整数间用空格隔开。
输入范例
5
-3 4 4 2 1
2输出范例
4 4
题目分析
这道题可以说是从一堆数中选出指定数目的最大的那些数,难点就在于不改变原序列中的顺序。比如让选出-3 1 -2 5 -10 0中间的最大的三个数,但是输出的时候只能输出1 5 0而不能按照其他顺序
解答
代码
#include "bits/stdc++.h"
using namespace std;
#define MVnum 100000
vector<int> arr;
void print(int m){
for(int i=0;i<m;i++){
cout<<arr.at(i)<<" ";
}
}
int main(){
int n,m;
cin>>n;
multiset<int >h;
for(int i=0;i<n;i++){
int k;
cin>>k;
arr.push_back(k);
h.insert(k);
}
cin>>m;
for(int i=0;i<n-m;i++){
for(int j=0;j<n;j++){
if(arr.at(j)==*h.begin()){
vector<int>::iterator iter=arr.begin()+j;
arr.erase(iter);
h.erase(h.begin());
break;
}
}
}
print(m);
return 0;
}
代码详解与难点分析(可无)
我一开始的想法,其实也是对于题目中的提示:
“子序列 定义为从一个数组里删除一些元素后,不改变剩下元素的顺序得到的数组。”
有一些错误理解,我的思路如下
我的关键思路
根据题目分析,在输入的时候设置两个数组,一个vector,用来保留原有的序列顺序,另一个multiset用来筛选出要删除那些元素,最后在vector中删除掉需要删除的,保留最大的那几个数字,并且按照原顺序输出。
其中在vector中删除需要删除元素那一步在代码实现上我想不到高效率的代码实现方法,只能使用较为笨拙的方法
for(int i=0;i<n-m;i++){
//此处的n-m指的是要被删除的数字的数目
for(int j=0;j<n;j++){
//这里是对vector进行一个遍历,把要删除的都给删除了
if(arr.at(j)==*h.begin()){
vector<int>::iterator iter=arr.begin()+j;
arr.erase(iter);
h.erase(h.begin());
break;
}
}
}
从这段代码上来说,他只能每针对一个要删除的数字就进行一次全局遍历搜索,很耗时,复杂度也高,将近O(n*n)的时间复杂度,很不划算,因此我上网参考了一下其他的优秀思路
改进后的思路
关键就在
sort(nums,nums+n,cmp2);//先把这个数组按从大到小的顺序排序
sort(nums,nums+m,cmp1);//再把最大的那几个数字按顺序从小到大排序
先把这个数组按从大到小的顺序排序
再把最大的那几个数字按顺序从小到大排序
改进后的代码
#include "bits/stdc++.h"
using namespace std;
#define MVnum 100000
struct pos{
int xu;//记载这个数的序号
int num;//记载这个数的大小
};
bool cmp1(const pos a,const pos b){
return a.xu<b.xu;
}
bool cmp2(const pos a,const pos b){
return a.num>b.num;
}
int main(){
int n,m;
cin>>n;
pos nums[1001];
for(int i=0;i<n;i++){
int k;
cin>>k;
nums[i].xu=i;
nums[i].num=k;
arr.push_back(k);
}
cin>>m;
sort(nums,nums+n,cmp2);//先把这个数组按从大到小的顺序排序
sort(nums,nums+m,cmp1);//再把最大的那几个数字按顺序从小到大排序
for(int i=0;i<m;i++){
cout<<nums[i].num<<" ";
}
return 0;
}
分析
算法的性能分析
改良之后是O(n*logN),有两个sort函数的运用,2*n*logn
该问题要求在给定的整数数组中找到一个长度为k的子序列,使得子序列的和最大,同时保持原数组顺序。初始解法使用multiset和vector,但效率较低。优化后的解决方案是先对数组进行降序排序,然后取出前k个最大值并按原顺序输出,提高了算法效率至O(n*logN)。

被折叠的 条评论
为什么被折叠?



