首先是大概的一个框架,然后重点说的是第12题。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
typedef struct LNode{
int data[100];
int length;
}SqList;
int n,m;
void InitList(SqList &L){ //构造顺序表
int i;
cin >> n;
for(i=0;i<n;i++)
cin >> L.data[i];
L.length=n;
}
void Trave(SqList &L){ //遍历顺序表
int i;
for(i=0;i<L.length;i++)
cout << L.data[i] << " ";
cout << endl;
cout << "The Length is "<< L.length <<endl;
}
void Reverse(SqList &L,int left,int right){ //逆置函数 ,从left处到right处的逆置
int i,num;
for(i=left;i<=(right-left)/2;i++){
num=L.data[right-i];
L.data[right-i]=L.data[i];
L.data[i]=num;
}
return ;
}
int main()
{
SqList L;
SqList La,Lb;
while(true){
InitList(L);
//Trave(L);
//InitList(La);
//Trave(La);
//f6(L);
//f7(L,La);
//Lb=f7(L,La);
//Trave(Lb);
//f8(L);
//Trave(L);
//f9(L,9);
//f12(L);
//cout << f12(L) << endl;
Trave(L);
}
return 0;
}
下面是一些题目的函数:
void f6(SqList &L){ //删除有序表中的重复元素
int i,k=0;
for(i=1;i<L.length;i++){
if(L.data[k]!=L.data[i]){
k++;
L.data[k]=L.data[i];
}
}
L.length=k+1;
}
SqList f7(SqList &La,SqList &Lb){ //合并两个有序表
SqList L;
int i,j,k=0;
for(i=0,j=0;i<La.length,j<Lb.length;){
if(La.data[i]>=Lb.data[j]){
L.data[k++]=Lb.data[j];
j++;
}
else if(La.data[i]<Lb.data[j]){
L.data[k++]=La.data[i];
i++;
}
}
if(i<La.length){
for(;i<La.length;i++){
L.data[k++]=La.data[i];
}
}
else if(j<Lb.length){
for(;j<Lb.length;j++){
L.data[k++]=Lb.data[j];
}
}
L.length=k;
return L;
}
void f8(SqList &L){ //顺序表L=(La,Lb)处理后L=(Lb,La)
int n,m;
cin >> n >> m;
Reverse(L,0,n+m-1);
//Trave(L);
Reverse(L,0,n-1);
Reverse(L,n,n+m-1);
}
void f9(SqList &L,int x){ //O(n) 查找元素x然后与后面节点交换数值
int i,j,k=0; //找不到的时候插入到有序表中
for(i=0;i<L.length;i++){
if(L.data[i]==x&&i!=L.length-1){
L.data[i]=L.data[i+1];
L.data[i+1]=x;
return ;
}
if(L.data[i]>x){
for(j=L.length;j>i;j--)
L.data[j]=L.data[j-1];
L.data[j]=x;
L.length++;
return ;
}
}
}
int f11(SqList &La,SqList &Lb,int n){ //找到两个升序列合并之后的中位数
int s1=0,d1=n-1,m1;
int s2=0,d2=n-1,m2;
while(s1!=d1||s2!=d2){ //时间复杂度O(log2n)
m1=(s1+d1)/2;
m2=(s2+d2)/2;
if(La.data[m1]==Lb.data[m2]) //两个序列的中位数相等的时候直接退出
return La.data[m1];
if(La.data[m1]>Lb.data[m2]){ //主要是二分的思想逐渐折半然后比较
if((s1+d1)%2==0){
s1=m1;
d2=m2;
}
else{
s1=m1+1;
d2=m2;
}
}
if(La.data[m1]<Lb.data[m2]){
if((s2+d2)%2==0){
d1=m1;
s2=m2;
}
else{
d1=m1;
s2=m2+1;
}
}
}
return La.data[s1]<Lb.data[s2]?La.data[s1]:Lb.data[s2];
}
第12题:【2013年统考题】找到到顺序表中的主元素,主元素的定义为出现的次数m>n/2,其中n是整个表的长度。
思考:
这个题目我最先想的是统计各个整数出现的个数,找到出现次数最多的数就时候选主元素。统计的话需要占用空间O(n),时间上只要跑两遍就可以了,第一遍统计第二遍比较多少,时间复杂度也是O(n)。但是参考答案只需要O(1)的空间复杂度,就是直接找候选主元素。
思路:
首先设置第一个元素为候选主元素,这个毋庸置疑。然后从第二个元素开始往后比较,相同的话计数count++;不相同的话count–;这里也好懂。**重点 **是当目前的元素与候选主元素不相同的时候,如果count<=0,说明了当前的候选主元素已经个数为0了,就是说每出现一次这个数(假设是num),都会有另外一个不相等的数进行抵消,num到目前的进度的时候达不到1/2.所以这个时候就必须要更换种子选手了,既然能当上种子选手也说明他在前面的序列中,出现的个数也是相当的多了,不然就会有其他的种子选手替换掉他。所以这时候就换下一个选手作为种子选手了。
当count<=0时,更换了种子选手,那么换掉的下一个种子选手可能还没有换之前的多怎么办呢。这个换个角度就能想明白了,既然作为一名种子选手就是想成为主元素的,那么主元素要求就是count>n/2,这就说明,走到最后的时候他能干掉所有其他的种子选手,是就是每出现一个不一样的元素,都能找一个元素给抵消掉,不管小伙伴来的有多晚,都能抵消掉。
看两组样例:
无论中间的时候种子选手会换给谁当,只要你是主元素,你都能给他们比下去,有这就够了。
int f12(SqList &L){ //找到出现次数大于length/2的元素
int i,num;
int count=1;
num=L.data[0]; //设置候选主元素为第一个
for(i=1;i<L.length;i++){ //查找候选主元素
if(L.data[i]==num)
count++; //与候选主元素相同则计数+1
else{
if(count>0) //计数count>0说明当前候选主元素不低于1/2
count--;
else{ //count<0则需要更换候选主元素
num=L.data[i];
count=1;
}
}
cout << i << ":" << count << " " << num << endl;
}
if(count>0){
count=0;
for(i=0;i<L.length;i++){ //统计实际出现的次数
if(L.data[i]==num)
count++;
}
}
if(count>L.length/2)
return num;
else
return -1;
}
int f13(SqList &L){ //时间复杂度O(n),空间:O(n)
int k=0;
int a[n+2];
int i;
memset(a,0,sizeof(a));
for(i=0;i<L.length;i++){ //找到最小的未出现的正整数
a[L.data[i]]++;
}
for(i=1;i<=n+1;i++){
if(a[i]==0)
return i;
}
}