{ }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 の XOR の技 *x ^= *y; *y ^= *x; *x ^= *y; は、二つのアドレスが同じ要素だと自分自身と XOR して 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);