首先是大概的一個框架,然後重點說的是第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;
}
}