{ }codelper
要素の入れ替え引数P0062

区間を反転する関数

一行目に n、二行目に整数 n 個のリストが与えられる。
三行目に命令の数 q が与えられ、続く q 行に "l r" が一つずつ与えられる(1 ≤ l ≤ r ≤ n、位置は 1 から数える)。
命令ごとにリストの l 番目から r 番目までをその場で逆順にせよ。
命令は与えられた順に、前の命令で変わったリストに続けて適用する。
すべての命令を終えたリストを空白一つ区切りで一行に出力せよ。
リストと区間を受け取って反転する関数を(二つの要素を入れ替える関数を使って)作って解いてみよう。

入力
1 ≤ n ≤ 1,000、1 ≤ q ≤ 1,000、すべての数は -1,000,000,000 以上 1,000,000,000 以下の整数
出力
一行:最後のリスト
例 1 · stdin
5
1 2 3 4 5
2
1 3
3 5
stdout
3 2 5 4 1
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

両端を入れ替えて内側へ一つずつ狭め、l < r のときだけ入れ替えます。
最後まで(i <= r)回ると真ん中を過ぎてもう一度入れ替え、元に戻ってしまいます。
二つの入れ替え:Python a[i], a[j] = a[j], a[i]、JavaScript・TypeScript [a[i], a[j]] = [a[j], a[i]]、C++ std::swap(a[i], a[j])、C# (a[i], a[j]) = (a[j], a[i])、Java・C・Craykon は一時変数 t。
**関数に渡すときが要点です。
** 数一つをそのまま渡すとどの言語でも値がコピーされるので、Python def swap(x, y): x, y = y, x や C void swap(int x, int y) は関数の中のコピーを入れ替えるだけで、リストはそのままです。
リストは Python・JavaScript・TypeScript・Java・C#・Craykon のどれでも同じリストが渡る(参照がコピーされる)ので、関数の中で要素を変えると外でも変わります。
だからリストと番号を渡せばよいのです。
C はアドレスを渡す void swap(int *x, int *y)、C# は ref int x で変数そのものを渡せます。
C++ は注意:void f(std::vector<int> a) は vector を丸ごとコピーして受け取るので変えても外はそのままです。
std::vector<int>& a(参照)で受け取ります。

Pythonmain.py · 15 行
def reverse_range(a, l, r):    """a[l..r](0부터)를 제자리에서 뒤집는다. 목록은 함수 밖의 것과 같은 것이다."""    while l < r:        a[l], a[r] = a[r], a[l]        l += 1        r -= 1  n = int(input())a = list(map(int, input().split()))q = int(input())for _ in range(q):    l, r = map(int, input().split())    reverse_range(a, l - 1, r - 1)print(*a)
JavaScriptmain.js · 16 行
const nums = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 배열은 같은 것이 넘어오므로 함수 안에서 바꾸면 밖에서도 바뀐다function reverseRange(a, l, r) {  while (l < r) {    [a[l], a[r]] = [a[r], a[l]];    l++;    r--;  }} const n = nums[0];const a = nums.slice(1, 1 + n);const q = nums[1 + n];for (let k = 0; k < q; k++) reverseRange(a, nums[2 + n + 2 * k] - 1, nums[3 + n + 2 * k] - 1);console.log(a.join(" "));
TypeScriptmain.ts · 17 行
import { readFileSync } from "node:fs";const nums: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 배열은 같은 것이 넘어오므로 함수 안에서 바꾸면 밖에서도 바뀐다function reverseRange(a: number[], l: number, r: number): void {  while (l < r) {    [a[l], a[r]] = [a[r], a[l]];    l++;    r--;  }} const n: number = nums[0];const a: number[] = nums.slice(1, 1 + n);const q: number = nums[1 + n];for (let k = 0; k < q; k++) reverseRange(a, nums[2 + n + 2 * k] - 1, nums[3 + n + 2 * k] - 1);console.log(a.join(" "));
JavaMain.java · 31 行
import java.util.Scanner;import java.util.StringJoiner; public class Main {    // 배열은 참조가 복사되어 넘어오므로 칸을 바꾸면 밖의 배열이 바뀐다    static void swap(int[] a, int i, int j) {        int t = a[i];        a[i] = a[j];        a[j] = t;    }     static void reverseRange(int[] a, int l, int r) {        while (l < r) swap(a, l++, r--);    }     public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt();        int[] a = new int[n];        for (int i = 0; i < n; i++) a[i] = sc.nextInt();        int q = sc.nextInt();        for (int k = 0; k < q; k++) {            int l = sc.nextInt();            int r = sc.nextInt();            reverseRange(a, l - 1, r - 1);        }        StringJoiner out = new StringJoiner(" ");        for (int v : a) out.add(String.valueOf(v));        System.out.println(out);    }}
C#Main.cs · 29 行
using System;using System.Linq; class Program{    // ref로 받으면 넘긴 변수 자체를 바꾼다(a[i], a[j] 칸을 직접)    static void Swap(ref int x, ref int y)    {        (x, y) = (y, x);    }     static void ReverseRange(int[] a, int l, int r)    {        while (l < r) Swap(ref a[l++], ref a[r--]);    }     static void Main()    {        Console.ReadLine();        int[] a = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();        int q = int.Parse(Console.ReadLine());        for (int k = 0; k < q; k++)        {            int[] lr = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();            ReverseRange(a, lr[0] - 1, lr[1] - 1);        }        Console.WriteLine(string.Join(" ", a));    }}
C++main.cpp · 22 行
#include <iostream>#include <utility>#include <vector> // vector를 &(참조)로 받아야 밖의 것이 바뀐다. 그냥 받으면 복사본만 바뀐다void reverse_range(std::vector<int>& a, int l, int r) {    while (l < r) std::swap(a[l++], a[r--]);} int main() {    int n, q, l, r;    std::cin >> n;    std::vector<int> a(n);    for (int& v : a) std::cin >> v;    std::cin >> q;    for (int k = 0; k < q; k++) {        std::cin >> l >> r;        reverse_range(a, l - 1, r - 1);    }    for (int i = 0; i < n; i++) std::cout << (i ? " " : "") << a[i];    std::cout << "\n";}
Cmain.c · 26 行
#include <stdio.h> /* 값이 아니라 주소를 받아야 넘긴 칸이 바뀐다 */void swap(int *x, int *y) {    int t = *x;    *x = *y;    *y = t;} void reverse_range(int *a, int l, int r) {    while (l < r) swap(&a[l++], &a[r--]);} int main(void) {    int n, q, l, r, a[1000];    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%d", &a[i]);    scanf("%d", &q);    for (int k = 0; k < q; k++) {        scanf("%d %d", &l, &r);        reverse_range(a, l - 1, r - 1);    }    for (int i = 0; i < n; i++) printf(i ? " %d" : "%d", a[i]);    putchar('\n');    return 0;}
Craykonmain.cray · 27 行
// 목록은 같은 것이 넘어오므로 함수 안에서 칸을 바꾸면 밖에서도 바뀐다자리바꾸기(목록, i, j){    t = 목록[i];    목록[i] = 목록[j];    목록[j] = t;} 구간뒤집기(목록, l, r){    間 (l < r)    {        자리바꾸기(목록, l, r);        l += 1;        r -= 1;    }} n = コンソール.行読み().数に();a = コンソール.数読み();q = コンソール.行読み().数に();繰り返す (k = 0; k < q; k++){    lr = コンソール.数読み();    구간뒤집기(a, lr[0] - 1, lr[1] - 1);}コンソール.書く(a);