{ }codelper
交换元素列表下标P0317

最矮的站最前,最高的站最后

体育课上 n 名学生站成一排。
老师恰好做两次交换来整理队伍。
第一次,身高最矮的学生和站在最前面的学生交换位置。
如果最矮的学生有多名,由其中站得最靠前的那名学生交换。
第二次,在完成第一次交换后的队伍中,身高最高的学生和站在最后面的学生交换位置。
如果最高的学生有多名,由其中站得最靠后的那名学生交换。
如果要交换的学生已经站在那个位置,就什么也不发生。
第一行给出 n,第二行从前到后依次给出学生的身高,用一个空格隔开。
把完成两次交换后的队伍的身高从前到后依次输出在一行,用一个空格隔开。

输入
1 ≤ n ≤ 1,000。
身高是 100 到 200 之间的整数
输出
一行:完成两次交换后的 n 个身高
样例 1 · stdin
4
180 160 150 170
stdout
150 160 170 180
样例 2 · stdin
6
160 150 175 150 175 160
stdout
150 160 175 150 160 175
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

查找位置和交换两个元素的工具,各语言不同。
第一次出现的位置:Python a.index(v),JS·TS a.indexOf(v),C# Array.IndexOf(a, v),C++ std::min_element(返回指向该元素的东西),Craykon a.查找位置(v)。
最后一次出现的位置:JS·TS a.lastIndexOf(v),C# Array.LastIndexOf(a, v),C++ 则像 std::max_element(a.rbegin(), a.rend()) 这样从后往前看。
Python 的列表没有从后面查找的方法,所以在反转后的列表里查找再换算位置;Java 数组、C、Craykon 用循环查找。
在循环里用 < 比较留下的是第一个位置,用 >= 比较留下的是最后一个位置。
交换:Python a[0], a[i] = a[i], a[0],JS·TS [a[0], a[i]] = [a[i], a[0]],C# (a[0], a[i]) = (a[i], a[0]),C++ std::swap(a.front(), *it);Java、C、Craykon 用临时变量。
五个陷阱:① 如果先把两个位置都找好再做两次交换,当最高的学生原本站在最前面时,第一次交换会把他移走,记下的位置就过时了(示例 1 变成 170 160 180 150)。
第二个位置要在第一次交换之后再找。
② 在 Python 中,如果像 a[0], a[a.index(min(a))] = a[a.index(min(a))], a[0] 这样把位置计算直接写在左边,左边是从前往后逐个赋值的,所以最小值存入 a[0] 之后 a.index(min(a)) 会重新计算,变成 0。
刚存入的值立刻被覆盖,交换等于没做(示例 1 变成 170 160 150 180)。
要先把位置存进变量。
③ 有多个相同身高时:用 <= 找最矮的会得到最后一个位置,而 C++ std::max_element(a.begin(), a.end()) 和 Python a.index(max(a)) 给出的是第一个位置。
值相同,但交换的对象不同,队伍也就不同(示例 2)。
④ C 的异或技巧 *x ^= *y; *y ^= *x; *x ^= *y; 在两个地址是同一个元素时,会和自己异或而变成 0。
最矮的学生已经站在最前面时正是这种情况。
⑤ 不用临时变量而写成 a[0] = a[i]; a[i] = a[0];,第一句就丢掉了 a[0] 原来的值,两个元素变得相同。

Pythonmain.py · 12 行
n = int(input())a = list(map(int, input().split())) # 가장 작은 키가 처음 나오는 자리를 먼저 변수에 담아 두고 맞바꾼다i = a.index(min(a))a[0], a[i] = a[i], a[0] # 가장 큰 키는 첫째 맞바꾸기를 마친 줄에서 다시 찾는다. 뒤집은 줄에서 처음 나오는 자리가 마지막 자리다j = n - 1 - a[::-1].index(max(a))a[n - 1], a[j] = a[j], a[n - 1] print(*a)
JavaScriptmain.js · 13 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const a = lines[1].trim().split(/\s+/).map(Number); // 가장 작은 키가 처음 나오는 자리const i = a.indexOf(Math.min(...a));[a[0], a[i]] = [a[i], a[0]]; // 가장 큰 키는 첫째 맞바꾸기를 마친 줄에서 다시 찾는다. lastIndexOf는 마지막으로 나오는 자리를 준다const j = a.lastIndexOf(Math.max(...a));[a[n - 1], a[j]] = [a[j], a[n - 1]]; console.log(a.join(" "));
TypeScriptmain.ts · 14 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const a: number[] = lines[1].trim().split(/\s+/).map(Number); // 가장 작은 키가 처음 나오는 자리const i: number = a.indexOf(Math.min(...a));[a[0], a[i]] = [a[i], a[0]]; // 가장 큰 키는 첫째 맞바꾸기를 마친 줄에서 다시 찾는다. lastIndexOf는 마지막으로 나오는 자리를 준다const j: number = a.lastIndexOf(Math.max(...a));[a[n - 1], a[j]] = [a[j], a[n - 1]]; console.log(a.join(" "));
JavaMain.java · 38 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    // Java에는 한 줄 맞바꾸기가 없다. 배열과 두 자리를 받아 임시 변수로 바꾼다    static void swap(int[] a, int i, int j) {        int tmp = a[i];        a[i] = a[j];        a[j] = tmp;    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        int[] a = new int[n];        StringTokenizer st = new StringTokenizer(in.readLine());        for (int k = 0; k < n; k++) a[k] = Integer.parseInt(st.nextToken());         // 가장 작은 키가 처음 나오는 자리: 더 작을 때만(<) 바꾼다        int i = 0;        for (int k = 1; k < n; k++) if (a[k] < a[i]) i = k;        swap(a, 0, i);         // 첫째 맞바꾸기를 마친 줄에서, 가장 큰 키가 마지막으로 나오는 자리: 같을 때도(>=) 바꾼다        int j = 0;        for (int k = 1; k < n; k++) if (a[k] >= a[j]) j = k;        swap(a, n - 1, j);         StringBuilder out = new StringBuilder();        for (int k = 0; k < n; k++) {            if (k > 0) out.append(' ');            out.append(a[k]);        }        System.out.println(out);    }}
C#Main.cs · 21 行
using System;using System.Linq; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        int[] a = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();         // 가장 작은 키가 처음 나오는 자리        int i = Array.IndexOf(a, a.Min());        (a[0], a[i]) = (a[i], a[0]);         // 가장 큰 키는 첫째 맞바꾸기를 마친 줄에서 다시 찾는다. LastIndexOf는 마지막으로 나오는 자리를 준다        int j = Array.LastIndexOf(a, a.Max());        (a[n - 1], a[j]) = (a[j], a[n - 1]);         Console.WriteLine(string.Join(" ", a));    }}
C++main.cpp · 21 行
#include <algorithm>#include <iostream>#include <vector> int main() {    int n;    std::cin >> n;    std::vector<int> a(n);    for (int& x : a) std::cin >> x;     // min_element는 가장 작은 값이 처음 나오는 자리를 가리킨다    auto smallest = std::min_element(a.begin(), a.end());    std::swap(a.front(), *smallest);     // max_element도 처음 나오는 자리를 준다. 뒤에서부터 보면(rbegin) 마지막으로 나오는 자리가 된다    auto tallest = std::max_element(a.rbegin(), a.rend());    std::swap(a.back(), *tallest);     for (int k = 0; k < n; k++) std::cout << (k ? " " : "") << a[k];    std::cout << '\n';}
Cmain.c · 29 行
#include <stdio.h> /* 값이 아니라 칸의 주소를 받아야 배열이 바뀐다 */static void swap(int *x, int *y) {    int tmp = *x;    *x = *y;    *y = tmp;} int main(void) {    int n;    static int a[1000];    scanf("%d", &n);    for (int k = 0; k < n; k++) scanf("%d", &a[k]);     /* 가장 작은 키가 처음 나오는 자리: 더 작을 때만(<) 바꾼다 */    int i = 0;    for (int k = 1; k < n; k++) if (a[k] < a[i]) i = k;    swap(&a[0], &a[i]);     /* 첫째 맞바꾸기를 마친 줄에서, 가장 큰 키가 마지막으로 나오는 자리: 같을 때도(>=) 바꾼다 */    int j = 0;    for (int k = 1; k < n; k++) if (a[k] >= a[j]) j = k;    swap(&a[n - 1], &a[j]);     for (int k = 0; k < n; k++) printf(k ? " %d" : "%d", a[k]);    printf("\n");    return 0;}
Craykonmain.cray · 34 行
// 두 자리를 맞바꾼다. 목록은 넘겨받은 그 목록이 바뀐다맞바꾸기(줄, i, j){    임시 = 줄[i];    줄[i] = 줄[j];    줄[j] = 임시;} n = 控制台.读行().转数字();a = 控制台.读数字(); // 가장 작은 키가 처음 나오는 자리: 더 작을 때만(<) 바꾼다i = 0;循环 (k = 1; k < n; k++){    如果 (a[k] < a[i])    {        i = k;    }}맞바꾸기(a, 0, i); // 첫째 맞바꾸기를 마친 줄에서, 가장 큰 키가 마지막으로 나오는 자리: 같을 때도(>=) 바꾼다j = 0;循环 (k = 1; k < n; k++){    如果 (a[k] >= a[j])    {        j = k;    }}맞바꾸기(a, n - 1, j); 控制台.输出(a);