机试_2_排序与查找_习题

排序与查找——习题

学习完第二章–排序与查找之后,当然要做相应地练习啦~

注:上述习题都可以在牛客进行测试。

例如,第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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

窝在角落里学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值