【排序】2024D-身高体重排序
【排序】2024D-身高体重排序
题目描述与示例
本题练习地址:https://www.algomooc.com/problem/P2550
题目描述
某学校举行运动会,学生们按编号(1、2、3.....n)
进行标识,
现需要按照身高由低到高排列,对身高相同的人,按体重由轻到重排列,对于身高体重都相同的人,维持原有的编号顺序关系。
请输出排列后的学生编号
输入描述
两个序列,每个序列由 n 个正整数组成(0 < n < 100)
。第一个序列中的数值代表身高,第二个序列中的数值代表体重。
输出描述
排列结果,每个数值都是原始序列中的学生编号,编号从 1
开始
示例一
输入
4
100 100 120 130
40 30 60 50
输出
2134
示例二
输入
3
90 110 90
45 60 45
输出
132
解题思路
我们一共有三个列表,身高列表h
,体重列表w
,以及编号列表idx
。
为了让身高、体重和编号的信息能够一一对应,我们使用zip()
函数将这三个列表里面的内容绑定为一个包含n
个三元元组的列表lst
,即
lst = list(zip(h, w, idx))
在排序方面,题目要求我们按身高从小到大排序,身高相同再按体重从小到大排序,身高体重相同则按照编号从小到大排序,均为升序排序。所以直接调用列表的方法sort()
或者内置函数sorted()
即可完成。即
lst.sort()
最终再将排序后的lst
中的编号信息取出来,再用字符串的join()
方法将排序后的编号顺序组合成一个字符串即可。即
print("".join([str(item[2]) for item in lst]))
面向对象思想
实际上,上述的解题思路已经包含了面向对象思想。
lst
中的每一个三元组item
,其实就代表了一个具体的人所包含的身高、体重、编号信息。
我们的代码是对这些若干的人来进行排序,而每个人它自身的信息包括身高、体重、编号则作为排序的依据。
后面的解法二分享了直接使用类与对象来解题的代码。
代码
解法一:使用三元组列表表示
Python
# 题目:2024D-身高提供排序
# 分值:100
# 作者:闭着眼睛学数理化
# 算法:直接调用排序API
# 代码看不懂的地方,请直接在群上提问
n = int(input())
h = list(map(int, input().split()))
w = list(map(int, input().split()))
idx = [i for i in range(1, n+1)] # 编号列表,1到n
lst = list(zip(h, w, idx)) # 身高、体重、编号整合为三元的元组,组成一个新的列表lst
lst.sort() # 直接对lst排序,会先按照身高排序,再按照体重排序,再按照编号排序
print("".join(str(item[2]) for item in lst)) # 排序后取编号,组成字符串,即为答案
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] h = new int[n];
int[] w = new int[n];
int[] idx = new int[n];
for (int i = 0; i < n; i++) {
h[i] = scanner.nextInt();
}
for (int i = 0; i < n; i++) {
w[i] = scanner.nextInt();
idx[i] = i + 1;
}
int[][] lst = new int[n][3];
for (int i = 0; i < n; i++) {
lst[i][0] = h[i];
lst[i][1] = w[i];
lst[i][2] = idx[i];
}
Arrays.sort(lst, Comparator.comparingInt((int[] a) -> a[0]).thenComparingInt((int[] a) -> a[1]).thenComparingInt((int[] a) -> a[2]));
StringBuilder result = new StringBuilder();
for (int i = 0; i < n; i++) {
result.append(lst[i][2]);
}
System.out.println(result);
}
}
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> h(n), w(n), idx(n);
for (int i = 0; i < n; ++i) {
cin >> h[i];
}
for (int i = 0; i < n; ++i) {
cin >> w[i];
idx[i] = i + 1;
}
vector<vector<int>> lst(n, vector<int>(3));
for (int i = 0; i < n; ++i) {
lst[i][0] = h[i];
lst[i][1] = w[i];
lst[i][2] = idx[i];
}
sort(lst.begin(), lst.end(), [](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0] || (a[0] == b[0] && (a[1] < b[1] || (a[1] == b[1] && a[2] < b[2])));
});
for (int i = 0; i < n; ++i) {
cout << lst[i][2];
}
cout << endl;
return 0;
}
解法二:使用类和对象表示
Python
# 题目:2024D-身高提供排序
# 分值:100
# 作者:闭着眼睛学数理化
# 算法:直接调用排序API
# 代码看不懂的地方,请直接在群上提问
# 构建People这个类,包含三个属性
# 身高、体重、编号
class People:
# 只包含初始化函数即可,不需要实现复杂的方法
def __init__(self, height, weight, idx):
self.height = height
self.weight = weight
self.idx = idx
n = int(input())
h = list(map(int, input().split()))
w = list(map(int, input().split()))
# 初始化列表为空
lst = list()
# 遍历所有下标
for i in range(n):
# 第i个下标,这个人的身高、体重、从1开始的编号
# 分别为h[i]、w[i]、i+1
# 用这三个数据来初始化一个对象people
people = People(h[i], w[i], i+1)
# 将这个对象储存入lst中
lst.append(people)
# 对lst中的对象,根据三个属性进行排序
lst.sort(key = lambda people: (people.height, people.weight, people.idx))
# 使用推导式输出答案
print("".join([str(people.idx) for people in lst]))
Java
import java.util.*;
class People {
int height;
int weight;
int idx;
// 初始化构造函数
public People(int height, int weight, int idx) {
this.height = height;
this.weight = weight;
this.idx = idx;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入人数
int n = scanner.nextInt();
// 输入每个人的身高
int[] h = new int[n];
for (int i = 0; i < n; i++) {
h[i] = scanner.nextInt();
}
// 输入每个人的体重
int[] w = new int[n];
for (int i = 0; i < n; i++) {
w[i] = scanner.nextInt();
}
// 初始化列表
List<People> lst = new ArrayList<>();
// 遍历所有下标
for (int i = 0; i < n; i++) {
// 用身高、体重和编号创建People对象并添加到列表
lst.add(new People(h[i], w[i], i + 1));
}
// 对列表进行排序,先按身高排序,再按体重排序,最后按编号排序
Collections.sort(lst, (a, b) -> {
if (a.height != b.height) {
return a.height - b.height;
} else if (a.weight != b.weight) {
return a.weight - b.weight;
} else {
return a.idx - b.idx;
}
});
// 使用StringBuilder构建输出结果
StringBuilder result = new StringBuilder();
for (People people : lst) {
result.append(people.idx);
}
// 输出结果
System.out.println(result.toString());
scanner.close();
}
}
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 初始化类,为了方便使用
// 三个属性定义为公有属性即可
class People {
public:
int height;
int weight;
int idx;
// 初始化构造函数
People(int h, int w, int id) : height(h), weight(w), idx(id) {}
};
// 比较函数,用于排序People对象
bool compare(const People &a, const People &b) {
if (a.height != b.height) {
return a.height < b.height;
} else if (a.weight != b.weight) {
return a.weight < b.weight;
} else {
return a.idx < b.idx;
}
}
int main() {
int n;
cin >> n;
// 身高和体重数组
vector<int> h(n);
vector<int> w(n);
// 输入身高
for (int i = 0; i < n; i++) {
cin >> h[i];
}
// 输入体重
for (int i = 0; i < n; i++) {
cin >> w[i];
}
// 初始化People对象的向量
vector<People> lst;
for (int i = 0; i < n; i++) {
// 用身高、体重和编号创建People对象并添加到列表
lst.emplace_back(h[i], w[i], i + 1);
}
// 使用自定义的compare函数进行排序
sort(lst.begin(), lst.end(), compare);
// 输出排序结果
for (const auto &people : lst) {
cout << people.idx;
}
cout << endl;
return 0;
}
时空复杂度
时间复杂度:O(NlogN)
。排序时间复杂度。
空间复杂度:O(N)
。
进阶
如果本题稍作修改,要求我们先按照身高升序排列,再按照体重降序排列,应该如何修改代码呢?这个时候就要祭出神器lambda
匿名函数了。语法如下:
lst.sort(key = lambda x: (x[0], -x[1]))
key
是sort()
方法或sorted()
内置函数的参数,表示排序的依据。lambda
匿名函数中的x
表示的就是lst
中的元素,即一个个的三元元组。由于sort()
默认的排序方式是升序,(x[0], -x[1])
表示对列表先按照x[0]
升序排列,在x[0]
相同的情况下再按照-x[1]
升序排列,即按照x[1]
降序排列。通过这样的方式,我们就实现了身高升序排列,再按照体重降序排列的目的。
对于原题目而言,如果我们也想显式地写出lambda
匿名函数,则代码为:
lst.sort(key = lambda x: (x[0], x[1]))
如果还想再把编号按照升序排列也显式地写出,则代码为
lst.sort(key = lambda x: (x[0], x[1], x[2]))
lambda
匿名函数的作用很多。除了sort()
之外,取最值的两个函数max()
和min()
中包含参数key
,表示取最大值或最小值的依据,譬如:
max(lst, key = lambda x: x[0] * x[1]))
表示取身高和体重之积最大的那个人所对应的三元元组。