描述
给你n个整数(n<=100),每个数都在(-1000~1000)之间,其中有很多重复的数字,请将重复的数字只保留一个,并将剩下的数由小到大排序并输出。
输入
输入有2行,
第1行为1个正整数,表示数的个数: N
第2行有N个用空格隔开的整数。
输出
每行一个整数,表示从小到大排好序的不相同的数。
输入样例 1复制
10 20 40 32 67 40 20 89 300 400 15
输出样例1复制
15 20 32 40 67 89 300 400
这题可以用普通的桶排来解决,但这篇文章的重点不在于讲这个
桶排解法
#include<bits/stdc++.h>
using namespace std;
int n,a[101],b[2001];
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
b[a[i]+1000]=1; // 数字加1000作为索引,将对应位置设为1
}
for(int i=0;i<2001;i++){
if(b[i]){
cout<<i-1000<<endl; // 输出对应的数(索引减去1000)
}
}
return 0;
}
而是一种我从同学不经意的一句话中提炼出来的——扎手排序(我自己起的名字)
原理如下:我们知道,当我们铅笔平齐放置在桌面上,将手放置于顶端,把手往下平移,先扎到手的就是最长的
把扎到手的依次拿出来,就实现了从大到小排序。
用C++如何实现这个过程呢?
我们可以把手看作是一个右指针r,而最短的那根铅笔处就是左指针l,这其实是一个抽象的对撞指针。
将r设置为最长的铅笔,将l设置为最短的铅笔,这样可以有效的缩短时间复杂度。并且这个排序好的是,它无视数据里是否有负数,但他也只能解决这一类去重排序题。
如何判断是否扎到手呢?
很简单,O(n)查找一下就行了
扎手排序从大到小排序模板:
#include<bits/stdc++.h>
using namespace std;
int s[10000],l=INT_MIN,r=INT_MAX,n;//l=maxn,r=minn
bool cz(int aa){
for(int i=0;i<n;i++){
if(s[i]==aa){
return 1;
}
}
return 0;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i];
l=max(l,s[i]);
r=min(r,s[i]);
}
while(l>=r){
if(cz(l)==1){
cout<<l<<" ";
}
l--;
}
return 0;
}
从小到大排序模板(同时也可以解决这题):
#include<bits/stdc++.h>
using namespace std;
int s[10000],l=INT_MIN,r=INT_MAX,n;//l=maxn,r=minn
bool cz(int aa){
for(int i=0;i<n;i++){
if(s[i]==aa){
return 1;
}
}
return 0;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i];
l=max(l,s[i]);
r=min(r,s[i]);
}
while(l>=r){
if(cz(r)==1){
cout<<r<<endl;
}
r++;
}
return 0;
}
当然,有人提出异议:对于要输出去重后数字个数的题怎么办?
很简单:
#include<bits/stdc++.h>
using namespace std;
int s[10000],l=INT_MIN,r=INT_MAX,n;//l=maxn,r=minn
bool cz(int aa){
for(int i=0;i<n;i++){
if(s[i]==aa){
return 1;
}
}
return 0;
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i];
l=max(l,s[i]);
r=min(r,s[i]);
}
int cnt=0;
//虽然看起来很智障
while(l>=r){
if(cz(r)==1){
cnt++;
}
r++;
}
cout<<cnt<<endl;
for(int i=0;i<n;i++){
//cin>>s[i];
l=max(l,s[i]);
r=min(r,s[i]);
}
while(l>=r){
if(cz(r)==1){
cout<<r<<endl;
}
r++;
}
return 0;
}