排序与查找——习题
学习完第二章–排序与查找之后,当然要做相应地练习啦~
注:上述习题都可以在牛客进行测试。
例如,第4题链接:奥运排序问题_牛客题霸_牛客网 (nowcoder.com),其他题目在“题目列表”中基本都可以找到。
另外,此文章仅仅是提供解题思路,并非最优解。
1 成绩排序–清华大学
描述:
查找和排序
题目:输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩
都按先录入排列在前的规则处理。
示例:
jack 70
peter 96
Tom 70
smith 67
从高到低 成绩
peter 96
jack 70
Tom 70
smith 67
从低到高 成绩
smith 67
jack 70
Tom 70
peter 96
输入描述:
注意一个case里面有多组样例,请用循环处理输入 输入多行,先输入要排序的人的个数,然后输入排序方法0(降序)或者1(升序)再分别输入他们的名字和成绩,以一个空格隔开。
输出描述:
按照指定方式输出名字和成绩,名字和成绩之间以一个空格隔开
示例1:
输入:
3
0
fang 90
yang 50
ning 70
输出:
fang 90
ning 70
yang 50
示例2:
输入:
3
1
fang 90
yang 50
ning 70
3
0
moolgouua 43
aebjag 87
b 67
输出:
yang 50
ning 70
fang 90
aebjag 87
b 67
moolgouua 43
说明:
第一组用例:
3
1
fang 90
yang 50
ning 70
升序排序为:
yang 50
ning 70
fang 90
第二组降序为:
aebjag 87
b 67
moolgouua 43
题解:
此题最大的特点就是排序方式不唯一,需要根据输入来确定采用升序排序还是降序排序,最简单的方法就是定义两个排序函数,一个降序一个升序。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Student {
string name;
int score;
//标记顺序
int flag;
};
/**
* 降序排序
* @param x
* @param y
* @param flag
* @return
*/
bool compareDescend(Student x, Student y) {
//按成绩从高到低排序
if (x.score == y.score) {
return x.flag < y.flag;
} else {
return x.score > y.score;
}
}
/**
* 升序排序
* @param x
* @param y
* @return
*/
bool compareAscend(Student x, Student y) {
//按成绩从低到高排序
if (x.score == y.score) {
return x.flag < y.flag;
} else {
return x.score < y.score;
}
}
void print(Student student[], int n) {
for (int i = 0; i < n; ++i) {
cout << student[i].name << " " << student[i].score << endl;
}
}
/**
* 成绩排序--清华大学
* @return
*/
int main() {
int m;
/*
* 排序标记,0--降序;1--升序
*/
int flag;
while (cin >> m >> flag) {
//动态开辟相应数组
Student *student = new Student[m];
for (int i = 0; i < m; ++i) {
cin >> student[i].name >> student[i].score;
student[i].flag = i;
}
if (flag == 0) {
//降序
sort(student, student + m, compareDescend);
} else {
//升序
sort(student, student + m, compareAscend);
}
print(student, m);
}
return 0;
}
2 特殊排序–华中科技大学
描述:
输入一系列整数,将其中最大的数挑出(如果有多个,则挑出一个即可),并将剩下的数进行排序,如果无剩余的数,则输出-1。
输入描述:
输入第一行包括1个整数N,1<=N<=1000,代表输入数据的个数。 接下来的一行有N个整数。
输出描述:
可能有多组测试数据,对于每组数据, 第一行输出一个整数,代表N个整数中的最大值,并将此值从数组中去除,将剩下的数进行排序。 第二行将排序的结果输出。
示例1
输入:
4
1 3 4 2
输出:
4
1 2 3
题解:
分析:
先将n个元素的原序列进行升序排序,arr[n-1]肯定就是最大值了,只需要遍历输出arr[0]~arr[n-2]即可。
特殊情况:n为1,则其自身就是最大值,我们只需输出其本身和-1即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 1000;
/**
* 特殊排序--华中科技大学
*/
int main() {
int n;
while (cin >> n) {
int num[MAX_NUM];
for (int i = 0; i < n; ++i) {
cin >> num[i];
}
if (n == 1) {
//特殊情况,只有一个整数,那自己就是最大值
cout << num[n - 1] << endl;
cout << "-1" << endl;
return 0;
}
//排序
sort(num, num + n);
//升序序列的最后面的值一定是最大值
int max = num[n - 1];
//输出最大值
cout << max << endl;
/*
* num[n-1]是最大值,不必输出
* 因此,循环到n-2即可
*/
for (int j = 0; j < n - 1; ++j) {
if (j != n - 2) {
cout << num[j] << " ";
} else {
//最后一个不需要空格,但是需要换行
cout << num[j] << endl;
}
}
}
return 0;
}
3 小白鼠排序–北京大学
描述:
N只小白鼠(1 <= N <= 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。帽子的颜色用“red”,“blue”等字符串来表示。不同的小白鼠可以戴相同颜色的帽子。
注:白鼠的重量用整数表示。
输入描述:
多案例输入,每个案例的输入第一行为一个整数N,表示小白鼠的数目。 下面有N行,每行是一只白鼠的信息。第一个为不大于100的正整数,表示白鼠的重量,;第二个为字符串,表示白鼠的帽子颜色,字符串长度不超过10个字符。 注意:白鼠的重量各不相同。
输出描述:
每个案例按照白鼠的重量从大到小的顺序输出白鼠的帽子颜色。
示例1:
输入:
3
30 red
50 blue
40 green
输出:
blue
green
red
题解:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 100;
/*
* 结构体保存小白鼠信息
*/
struct Mouse {
int weight;
string color;
};
/**
* 按体重降序排序
* @param x
* @param y
* @return
*/
bool compareAscend(Mouse x, Mouse y) {
return x.weight > y.weight;
}
/**
* 小白鼠排队
* @return
*/
int main() {
Mouse mouse[MAX_NUM];
int n;
while (cin >> n) {
for (int i = 0; i < n; ++i) {
cin >> mouse[i].weight >> mouse[i].color;
}
sort(mouse, mouse + n, compareAscend);
for (int i = 0; i < n; ++i) {
cout << mouse[i].color << endl;
}
}
return 0;
}
cc
4 奥运排序问题–浙江大学(▲)
描述:
按要求,给国家进行排名。
输入描述:
有多组数据。
第一行给出国家数N,要求排名的国家数M,国家号从0到N-1。
第二行开始的N行给定国家或地区的奥运金牌数,奖牌数,人口数(百万)。
接下来一行给出M个国家号。
输出描述:
排序有4种方式: 金牌总数、奖牌总数、金牌人口比例、奖牌人口比例
对每个国家给出最佳排名排名方式、最终排名,格式为:“排名:排名方式”
注:如果有相同的最终排名,则输出排名方式最小的那种排名,对于排名方式,金牌总数 < 奖牌总数 < 金牌人口比例 < 奖牌人口比例
注:如果有并列排名的情况,即如果出现金牌总数为100、90、90、80。则排名为1、2、2、4, 每组数据后加一个空行。
示例1
输入:
4 4
4 8 1
6 6 2
4 8 2
2 12 4
0 1 2 3
4 2
8 10 1
8 11 2
8 12 3
8 13 4
0 3
输出:
1:3
1:1
2:1
1:2
1:1
1:1
题解:
这道题还是比较复杂了,做了好久,同时也参考了一下别人的解法。
分析:
我们先定义结构体,记录每个国家的金牌数、奖牌总数、人口、初始序号、金牌排序、奖牌排序、金牌人口比例排序、奖牌人口比例排序,前4个指标由用户赋值,后4个指标计算后再赋值。
/*
* 国家
*/
struct Country {
int goldMedal; //金牌数
int medal; //奖牌总数
int population; //人口
int initOrder; //国家号
int goldMedalRank; //金牌排序
int medalRank; //奖牌排序
int ratio4GoldMedalAndPopulationRank; //金牌人口比例排序
int ratio4MedalAndPopulationRank; //奖牌人口比例排序
};
同时,我们自定义五个排序函数,对金牌、奖牌、金牌人口比例、奖牌人口比例、初始序号分别进行排序。
bool compareByGoldMedal(Country x, Country y);
bool compareByMedal(Country x, Country y);
bool compareByRatio4GoldMedalAndPopulation(Country x, Country y);
bool compareByRatio4MedalAndPopulation(Country x, Country y);
bool compareByInitOrder(Country x, Country y);
以对金牌总数排序为例,排序之后,则金牌总数最多的国家排在第一,即country[0].goldMedalRank 赋值为1,然后我们遍历所有国家,如果金牌相等则并列第一,如果不等,则依次排序。
/*
* 对金牌数进行排序
*/
sort(country, country + n, compareByGoldMedal);
//排序后的第一个排名就是1
country[0].goldMedalRank = 1;
for (int i = 1; i < n; ++i) {
if (country[i - 1].goldMedal == country[i].goldMedal) {
//金牌总数相同,则排名相同
country[i].goldMedalRank = country[i - 1].goldMedalRank;
} else {
//金牌总数不同,则排名变为 i+1
country[i].goldMedalRank = i + 1;
}
}
四个指标排序完成后,再将排序后的序列还原,最后再输出题目要求排名的国家。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
/*
* 国家
*/
struct Country {
int goldMedal; //金牌数
int medal; //奖牌总数
int population; //人口
int initOrder; //国家号
int goldMedalRank; //金牌排序
int medalRank; //奖牌排序
int ratio4GoldMedalAndPopulationRank; //金牌人口比例排序
int ratio4MedalAndPopulationRank; //奖牌人口比例排序
};
/**
* 金牌总数排序
* @param x
* @param y
* @return
*/
bool compareByGoldMedal(Country x, Country y) {
return x.goldMedal > y.goldMedal;
}
/**
* 奖牌总数排序
* @param x
* @param y
* @return
*/
bool compareByMedal(Country x, Country y) {
return x.medal > y.medal;
}
/**
* 金牌人口比例排序
* @param x
* @param y
* @return
*/
bool compareByRatio4GoldMedalAndPopulation(Country x, Country y) {
double xRatio = x.goldMedal * 1.0 / x.population;
double yRatio = y.goldMedal * 1.0 / y.population;
return xRatio > yRatio;
}
/**
* 奖牌人口排序
* @param x
* @param y
* @return
*/
bool compareByRatio4MedalAndPopulation(Country x, Country y) {
double xRatio = x.medal * 1.0 / x.population;
double yRatio = y.medal * 1.0 / y.population;
return xRatio > yRatio;
}
/**
* 按初始顺序排序,将排序后的序列还原
* @param x
* @param y
* @return
*/
bool compareByInitOrder(Country x, Country y) {
return x.initOrder < y.initOrder;
}
/**
* 奥运排序问题--北京大学
* @return
*/
int main() {
int n; //国家数
int m; //要求排名的国家数
while (cin >> n >> m) {
Country *country = new Country[n];
for (int i = 0; i < n; ++i) {
country[i].initOrder = i;
cin >> country[i].goldMedal >> country[i].medal >> country[i].population;
}
int *waitSort = new int[m];
for (int j = 0; j < m; ++j) {
cin >> waitSort[j];
}
/*
* 对金牌数进行排序
*/
sort(country, country + n, compareByGoldMedal);
//排序后的第一个排名就是1
country[0].goldMedalRank = 1;
for (int i = 1; i < n; ++i) {
if (country[i - 1].goldMedal == country[i].goldMedal) {
//金牌总数相同,则排名相同
country[i].goldMedalRank = country[i - 1].goldMedalRank;
} else {
//金牌总数不同,则排名变为 i+1
country[i].goldMedalRank = i + 1;
}
}
/*
* 对奖牌总数进行排序
*/
sort(country, country + n, compareByMedal);
country[0].medalRank = 1;
for (int i = 0; i < n; ++i) {
if (country[i - 1].medal == country[i].medal) {
country[i].medalRank = country[i - 1].medalRank;
} else {
country[i].medalRank = i + 1;
}
}
/*
* 对金牌人口比例进行排序
*/
sort(country, country + n, compareByRatio4GoldMedalAndPopulation);
country[0].ratio4GoldMedalAndPopulationRank = 1;
for (int i = 0; i < n; ++i) {
if (1.0 * country[i].goldMedal / country[i].population ==
1.0 * country[i - 1].goldMedal / country[i - 1].population) {
country[i].ratio4GoldMedalAndPopulationRank = country[i - 1].ratio4GoldMedalAndPopulationRank;
} else {
country[i].ratio4GoldMedalAndPopulationRank = i + 1;
}
}
/*
* 对奖牌人口比例进行排序
*/
sort(country, country + n, compareByRatio4MedalAndPopulation);
country[0].ratio4MedalAndPopulationRank = 1;
for (int i = 0; i < n; ++i) {
if (1.0 * country[i].medal / country[i].population ==
1.0 * country[i - 1].medal / country[i - 1].population) {
country[i].ratio4MedalAndPopulationRank = country[i - 1].ratio4MedalAndPopulationRank;
} else {
country[i].ratio4MedalAndPopulationRank = i + 1;
}
}
/*
* 将序列按initOrder排序,即回归原本的序列
* 输出需要排名的国家
* 输出该国家四种排名中最小的一个
*/
sort(country, country + n, compareByInitOrder);
for (int i = 0; i < m; ++i) {
int index = waitSort[i];
Country cur = country[index];
int r1 = cur.goldMedalRank;
int r2 = cur.medalRank;
int r3 = cur.ratio4GoldMedalAndPopulationRank;
int r4 = cur.ratio4MedalAndPopulationRank;
if (r1 <= r2 && r1 <= r3 && r1 <= r4) {
cout << r1 << ":" << 1 << endl;
} else if (r2 <= r3 && r2 <= r4 && r2 <= r1) {
cout << r2 << ":" << 2 << endl;
} else if (r3 <= r4 && r3 <= r2 && r3 <= r1) {
cout << r3 << ":" << 3 << endl;
} else {
cout << r4 << ":" << 4 << endl;
}
}
cout << endl;
}
return 0;
}
5 找x–哈尔滨工业大学
描述:
输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。
输入描述:
测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。
输出描述:
对于每组输入,请输出结果。
示例1
输入:
2
1 3
0
输出:
-1
题解:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 200;
int num[MAX_NUM];
/**
* 找x哈尔滨工业大学
* @return
*/
int main() {
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> num[i];
}
int x;
cin >> x;
int ans = -1;
for (int j = 0; j < n; ++j) {
if (num[j] == x) {
ans = j;
break;
}
}
cout << ans << endl;
return 0;
}
6 找最小数–北京邮电大学
描述:
第一行输入一个数n,1 <= n <= 1000,下面输入n行数据,每一行有两个数,分别是x y。输出一组x y,该组数据是所有数据中x最小,且在x相等的情况下y最小的。
输入描述:
输入有多组数据。 每组输入n,然后输入n个整数对。
输出描述:
输出最小的整数对。
示例1:
输入:
5
3 3
2 2
5 5
2 1
3 6
输出:
2 1
题解:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 1000;
struct Data {
int x;
int y;
};
/**
* 按x升序排序,若x相等则按y升序排序
* @param a
* @param b
* @return
*/
bool compare(Data a, Data b) {
if (a.x == b.x) {
return a.y < b.y;
} else {
return a.x < b.x;
}
}
/**
* 找最小数--北京邮电大学
* @return
*/
int main() {
int n;
Data *data;
while (cin >> n) {
data = new Data[n];
for (int i = 0; i < n; ++i) {
cin >> data[i].x >> data[i].y;
}
//升序排序
sort(data, data + n, compare);
//输出data[0]即可
cout << data[0].x << " " << data[0].y << endl;
}
return 0;
}
7 打印极值点下标–北京大学
描述
在一个整数数组上,对于下标为i的整数,如果它大于所有它相邻的整数, 或者小于所有它相邻的整数,则称该整数为一个极值点,极值点的下标就是i。
输入描述:
每个案例第一行为此数组元素个数k(4<k<80),第二行是k个整数,每两个整数之间用空格分隔
输出描述:
每个案例输出为n个数字(其中n为该案例中极值点的个数):每个数字对应相应数组的相应极值点下标值,下标值之间用空格分隔。
示例1:
输入:
10
10 12 12 11 11 12 23 24 12 12
15
12 12 122 112 222 211 222 221 76 36 31 234 256 76 76
15
12 14 122 112 222 222 222 221 76 36 31 234 256 76 73
输出:
0 7
2 3 4 5 6 10 12
0 2 3 10 12 14
题解:
对于开头(索引0),只需要判断与num[1]不相等即可
对于结尾元素(索引n-1),只需要判断与num[n-2]不相等即可
而对于中间元素,只需判断是否满足以下条件之一
1. num[i] < num[i+1] && num[i] < num[i-1]
2. num[i] > num[i+1] && num[i] > num[i-1]
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 80;
/**
* 打印极值点下标--北京大学
* 简单遍历,除去首尾,其余都分别与左右相比较
* @return
*/
int main() {
int num[MAX_NUM];
int n;
while (cin >> n) {
for (int i = 0; i < n; ++i) {
cin >> num[i];
}
//判断索引0
if (num[0] != num[1]) {
cout << "0 ";
}
//遍历判断中间的元素
for (int j = 1; j < n - 1; ++j) {
if (num[j] > num[j - 1] && num[j] > num[j + 1]) {
cout << j << " ";
} else if (num[j] < num[j - 1] && num[j] < num[j + 1]) {
cout << j << " ";
}
}
//判断索引n-1
if (num[n - 1] != num[n - 2]) {
cout << n - 1;
}
}
return 0;
}
8 找位置–华中科技大学
描述:
对给定的一个字符串,找出有重复的字符,并给出其位置,如:abcaaAB12ab12
输出:a,1;a,4;a,5;a,10,b,2;b,11,1,8;1,12, 2,9;2,13。
输入描述:
输入包括一个由字母和数字组成的字符串,其长度不超过100。
输出描述:
可能有多组测试数据,对于每组数据, 按照样例输出的格式将字符出现的位置标出。 1、下标从0开始。 2、相同的字母在一行表示出其出现过的位置。
示例1:
输入:
abcaaAB12ab12
输出:
a:0,a:3,a:4,a:9
b:1,b:10
1:7,1:11
2:8,2:12
题解:
先采用空间换时间的策略,用一个数组来统计字符串每个字符出现的次数(以每个字符的ASCII码作为索引下标)。
//哈希表
struct HashTable {
int len; //记录position数组的长度,即元素出现的次数
int *position; //数组记录字符出现的索引
};
统计完之后,再遍历一遍字符串,查看该字符ASCII码对应的索引下标的元素值是否大于1,如果大于1则输出该字符。
输出完成之后,将其元素值修改为0,防止后面相同的字符又重复输出。
注:用一个人flag标志位来控制“,”的输出。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_NUM = 75;
//哈希表
struct HashTable {
int len; //记录position数组的长度,即元素出现的次数
int *position; //数组记录字符出现的索引
};
/**
* 找位置
* @return
*/
int main() {
string str;
while (cin >> str) {
int length = str.size();
HashTable table[MAX_NUM];
//初始化哈希表
for (int i = 0; i < MAX_NUM; ++i) {
table[i].len = 0;
table[i].position = new int{0};
}
/*
* 遍历字符串
* 1.统计每个字符出现的次数
* 2.记录相同字符出现的位置索引
*/
for (int j = 0; j < length; ++j) {
int index = str[j] - '0';
table[index].position[table[index].len] = j;
table[index].len++;
}
for (int k = 0; k < length; ++k) {
//flag标记位,第一个不打印",",后续每个字符都打印","
bool flag = false;
int index = str[k] - '0';
if (table[index].len > 1) {
//该字符超过两个,则打印该字符及其索引
for (int i = 0; i < table[index].len; ++i) {
if (flag) {
cout << ",";
}
//打印字符
cout << str[k] << ":" << table[index].position[i];
flag = true;
}
cout << endl;
}
table[index].len = 0;
}
}
return 0;
}