第1关:二维数组中的元素查重
任务描述
设二维数组a[1..m, 1..n] 含有m*n 个整数。写一个算法判断a中所有元素是否互不相同。
编程要求
输入
多组数据,每组数据有m+1行,第一行为二维数组的行数m和列数n,之后m行为输入的二维数组。当n=0且m=0时输入结束。
输出
对于每组数据分别输出一行,若二维数组中存在相等元素则输出“YES”,否则输出“NO”。
#include<iostream>
#define MAXSIZE 124
using namespace std;
int IsEqual(int a[MAXSIZE][MAXSIZE],int m,int n)
{//判断a中所有元素是否互不相同,存在相等元素则返回1,输出“YES”,否则返回0,输出“NO”
/**************begin************/
int i,j,p,k;
for(i=0;i<m;i++)
for(j=0;j<n-1;j++) //判断a[i][j]是否重复
{
for(p=j+1;p<n;p++) //用p来保存列,和同行其他元素比较
if(a[i][j]==a[i][p]) //只要有一个相同,就返回1
{
cout<<"YES"<<endl;
return 1;
}
for(k=i+1;k<m;k++) //用k来保存行,和第i+1行及以后元素比较
for(p=0;p<n;p++) //用p来保存列,比较第k+1行的数据
if(a[i][j]==a[k][p])
{
cout<<"YES"<<endl;
return 1;
}
}
cout<<"NO"<<endl; //元素互不相同
return 0;
/**************end************/
}
int main()
{
int m,n; //行数m和列数n
while(cin>>m>>n&&m!=0&&n!=0)
{
int a[MAXSIZE][MAXSIZE],i,j;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
cin>>a[i][j]; //输入二维数组
IsEqual(a,m,n); //二维数组中的元素查重
}
return 0;
}
第2关:数组的正负数分割排序
任务描述
设任意n个整数存放于数组A[1..n]中,试编写算法,将所有正数排在所有负数前面(要求:正(负)数序列中数的相对顺序不变,算法时间复杂度为O(n))。
编程要求
输入
多组数据,每组数据有两行,第一行为数组中存放的数的个数n,第二行为n个整数。当n=0时输入结束。
输出
对于每组数据分别输出一行,为分割排序后的数组。
#include <iostream>
using namespace std;
void SplitSort(int *A,int n)
{//正负数分割排序
/**************begin************/
//这段代码的思路是使用冒泡排序的方式将正数移动到数组的左侧,而将负数移动到数组的右侧。通过每次比较相邻的两个元素,并交换它们的位置(如果需要),可以将整个数组分成两部分:正数和负数。这个过程从数组的最后一个元素开始,一直进行到数组的第一个元素。每次循环中,如果遇到一个负数,就将它与后面的正数交换位置,并将计数器 cnt 加 1。这样,最终得到的数组将满足要求:正数在前,负数在后。
int i,j,cnt=0,temp;
for(i=n-1;i>=0;i--)
{
if(A[i]<0)
{
cnt++;
for(j=i;j<=n-cnt-1;j++)
{
temp=A[j+1];
A[j+1]=A[j];
A[j]=temp;
}
}
}
/**************end************/
}
void PrintA(int *A,int n)
{//依次输出数组中的数据
for(int i=0;i<n;i++)
{
cout<<A[i];
if(i!=n-1)cout<<" ";
else cout<<endl;
}
}
int main()
{
int n;
while(cin>>n)
{
if(n==0) break;
int *A = new int[n];
for(int i=0;i<n;i++) cin>>A[i];
SplitSort(A,n);
PrintA(A,n);
}
return 0;
}
第3关:数组的循环左移
任务描述
设将n(n>1)个整数存放到一维数组R中。试设计一个在时间和空间两方面都尽可能高效的算法,将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(x0, x1…, xn-1)变换为(xp,xp+1,…,xn-1,x0,x1,…,xp-1)。
编程要求
输入
多组数据,每组数据有三行。第一行为一个整数n,代表数组R中有n个元素。第二行为数组R中的n个元素(元素之间用空格分隔)。第三行为一个整数p,代表将R中的序列循环左移p个位置。当n等于0时,输入结束。
输出
每组数据输出一行,为移动后的数组R中所存放的序列。每两个数之间用空格分隔。
#include <iostream>
using namespace std;
void Reverse(int R[],int left,int right)
{//将数组R中的数据原地逆置
/**************begin************/
int i = left, j = right;
while(i < j){
int temp = R[i];
R[i] = R[j];
R[j] = temp;
i++;
j--;
}
/**************end************/
}
void LeftShift(int R[],int n,int p)
{//将长度为n的数组R中的数据循环左移p个位置
/**************begin************/
//如果p的值在0到n-1的范围内,这个函数会将数组R中的数据循环左移p个位置。具体步骤如下:
//首先,它会调用Reverse函数,将整个数组逆序。这一步其实是为了方便接下来的步骤,因为逆序后,最右边的元素就变到了最左边,左边的元素则变到了右边。
//然后,它再次调用Reverse函数,将前n-p个元素逆序。这样原来在右边的元素(也就是原来在左边的元素)就回到了它们原来在数组中的位置。
//最后,它再次调用Reverse函数,将剩下的p个元素逆序。这样原来在最右边的元素就移到了它们新的位置。
if(p>0&&p<n)
{
Reverse(R,0,n-1); //将全部数据逆置
Reverse(R,0,n-p-1); //将前n-p个数据逆置
Reverse(R,n-p,n-1); //将后p个数据逆置
}
/**************end************/
}
void PrintA(int R[],int n)
{//依次输出数组中的数据
for(int i=0;i<n;i++)
{
cout<<R[i];
if(i==n-1)
cout<<endl;
else
cout<<" ";
}
}
int main()
{
int n;
while(cin>>n)
{
if(n==0) break;
int *R = new int[n];
for(int i=0;i<n;i++) //输入数据
{
cin>>R[i];
}
int p; //p代表将R中的序列循环左移p个位置
cin>>p;
LeftShift(R,n,p); //数组的循环左移
PrintA(R,n); //输出数据
}
return 0;
}
第4关:数组的主元素查询
任务描述
已知一个整数序列A=(a0, a1,…an-1),其中0≤ai<n(0≤i<n)。若存在ap1=ap2…=apm=x 且m>n/2(0≤pk<n,1≤k≤m),则称x为A的主元素。例如A=(0,5,5,3,5,7,5,5),则5为主元素;又如A=(0,5,5,3,5,1,5,7),则A中没有主元素。假设A中的n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1。
编程要求
输入
多组数据,每组数据两行。第一行为一个整数n,代表数组中有n个元素。第二行为数组中的n个元素(元素之间用空格分隔)。当n等于0时,输入结束。
输出
每组数据输出一行,若数组中存在主元素,输出主元素的值,若数组中不存在主元素,则输出-1。
#include <iostream>
using namespace std;
int MainElement(int a[],int n)
{//求整数序列a的主元素
/**************begin************/
//数组的主元素定义为数组中出现次数大于等于数组长度一半的元素
int cnt=1,i; //cnt用来计数
int key=a[0]; //key用来保存候选主元素,初始为a[0]
for(i=1;i<n;i++) //扫描数组,选取候选主元素
{
if(a[i]==key) cnt++; //侯选主元素计数加1
else
{
if(cnt>0) cnt--; //非候选主元素计数减1
else //更换候选主元素,重新计数
{
key=a[i];
cnt=1;
}
}
}
if(cnt>0)
for(i=0,cnt=0;i<n;i++) //统计候选主元素的实际出现次数
if(a[i]==key) cnt++;
if(cnt>n/2) return key; //确认主元素
else return -1; //不存在主元素
/**************end************/
}
int main()
{
int n;
while(cin>>n)
{
if(n==0) break;
int *a=new int[n];
for(int i=0;i<n;i++) //输入数据
{
cin>>a[i];
}
cout<<MainElement(a,n)<<endl; //输出主元素的值
}
return 0;
}
第5关:找出数组中和为目标值的两个数
任务描述
设计算法,找出数组中相加之和为目标值的两个数,并输出这两个数的下标。每组输入仅对应一种答案,相同的元素不能被重复利用。
编程要求
输入
多组数据,每组数据有三行,第一行为数组的大小n,第二行为n个元素(元素之间用空格分隔),第三行为目标值,当n=0时输入结束。
输出
对于每组数据分别输出一样,输出两个数的下标(元素间用空格分隔)。
#include<iostream>
using namespace std;
void CreateArray(int *a,int n)
{//创建数组
for(int i=0;i<n;i++)
{
cin>>a[i];
}
}
void Find(int *a,int n,int x)
{//找出数组中和为目标值的两个数
/**************begin************/
for(int i=0;i<n;i++) //遍历数组
{
for(int j=i+1;j<n;j++) //每趟j指向a[i]后一个元素
{
if(a[i]+a[j]==x) //判断是否满足相加之和为目标值
{
cout<<i<<" "<<j<< endl;
break;
}
}
}
/**************end************/
}
int main()
{
int n;
while(cin>>n)
{
if(n==0) break;
int *a=new int[n];
CreateArray(a,n); //创建数组
int x;
cin>>x;
Find(a,n,x);
}
return 0;
}
第6关:查找数组中缺失的数字
任务描述
在大小为n的数组中,仅存在大小为[1,n]的数字,数组中的元素有些出现了两次,有些出现了一次,有的数字没有出现。设计一个算法在空间复杂度为O(1),时间复杂度为O(n)的情况下找到这些没有出现的数字。假设储存结果的数组不算在额外空间之内。
编程要求
输入
多组数据,每组数据有两行,第一行为数组的长度n,第二行为数组的n个元素(元素之间用空格分隔),当n=0时输入结束。
输出
对于每组数据分别输出一行,输出缺失的数据(元素之间用空格分隔),如果数据未缺失,输出Not Found。
#include<iostream>
#include<string>
#include<cmath>
#define MAXSIZE 1024
using namespace std;
void FindMissNumber(int *a,int n)
{//指定数字组中的位数
/**************begin************/
// 通过将对应位置的元素变为负数来标记出现过的数字
// 通过将对应位置的元素变为负数来标记出现过的数字
// for (int i = 0; i < n; i++) {
// int index = abs(a[i]) - 1;
// if (a[index] > 0) {
// a[index] = -a[index];
// }
// }
// // 输出缺失的数字
// bool found = false;
// for (int i = 0; i < n; i++) {
// if (a[i] > 0) {
// cout << i + 1;
// found = true;
// // 判断是否为最后一个数字,不是则输出空格
// if (i != n - 1) {
// cout << " ";
// }
// }
// }
// // 如果没有缺失的数字,输出 "Not Found"
// if (!found) {
// cout << "Not Found";
// }
// cout << endl;
int index; //待检查的牵引指数
for(int i=0;i<n;i++) //从原始数字组中查看列表中[i]数字组的第一个元素,然后将数字组元素的正确值作为倒数
{
index=abs(a[i])-1; //更新要检查的牵引指数
if(a[index]>0)
{
a[index]=a[index]*(-1);
}
}
int *result=new int[MAXSIZE]{0}; //初始存储的结果数是结果
int sub=0;
for(int i=0;i<n;i++)
{
if(a[i]>0) //如果a[i]大于0,输入结果编号组
{
result[sub++]=i+1;
}
}
if(!sub) //结果编号分组在标签Sub下,输出Not Found
{
cout<<"Not Found"<<endl;
}
else //否则//输出存储的数据
{
for (int i=0;i<sub-1;i++)
cout<<result[i]<< " ";
cout<<result[sub - 1]<<endl;
}
/**************end************/
}
int main()
{
int n;
while (cin>>n)
{
if(n==0) break;
int *a=new int[MAXSIZE]{0}; //初始编号集合中的所有元素都小于0
for(int i=0;i<n;i++) //将输入数据输入数据组
{
cin>>a[i];
}
FindMissNumber(a,n);
}
return 0;
}