Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで隣接要素の条件付きスワップにより配列をソートできるか判定する方法

問題の概要

0からn-1までの範囲に含まれる要素で構成された、順序がバラバラの数値配列numsがあるとします。この配列に対しては、「隣接する2つの要素の絶対差が1である場合に限り」隣接要素同士を入れ替える(スワップする)ことができます。必要な回数だけスワップを繰り返せるとして、このnumsを昇順にソートできるかどうかを判定するのが目的です。

例えば、入力が nums = [1, 0, 3, 2, 5, 4] の場合、出力はTrueになります。これは、ペア (1, 0)、(3, 2)、(5, 4) をそれぞれスワップすることで、[0, 1, 2, 3, 4, 5] というソート済みの配列を作れるためです。

解法のアプローチ

この問題は、配列を左から順に走査しながら、以下の手順で判定できます。

  • i を 0 から numsのサイズ - 2 まで繰り返します。
  • もし nums[i] > nums[i+1](逆転が発生している)ならば:
    • nums[i] - nums[i+1] がちょうど1であれば、nums[i] と nums[i+1] を交換します。
    • それ以外の場合は、これ以上ソートできないため False を返します。

ループが最後まで完了すれば、すべての逆転を解消できたことになるので True を返します。

なぜこの方法で正しく判定できるのかというと、絶対差が1の隣接要素しか交換できないため、各要素は「自分の値 ± 1」との位置関係しか変更できません。左から貪欲に(greedyに)逆転を解消していき、解消できない逆転が見つかった時点でFalseとなる、シンプルかつ確実な仕組みです。

実装例

理解を深めるために、以下の実装例を見てみましょう。

def solve(nums):
    for i in range(len(nums) - 1):
        if nums[i] > nums[i+1]:
            if nums[i] - nums[i+1] == 1:
                nums[i], nums[i+1] = nums[i+1], nums[i]
            else:
                return False
    return True

nums = [1, 0, 3, 2, 5, 4]
print(solve(nums))

入力

[1, 0, 3, 2, 5, 4]

出力

True

計算量について

このアルゴリズムの時間計算量は O(n)、空間計算量は O(1)(入力配列をその場で書き換える場合)です。配列を一度走査するだけで判定できるため、非常に効率的な解法と言えます。

  1. Pythonでマージソートの再帰呼び出しがちょうどk回になる配列を見つける方法

    問題の概要2つの整数 a と b が与えられたとき、[1, a] の範囲の値をすべて含み、再帰的なマージソート関数がちょうど b 回呼び出されるような配列を見つけることを考えます。例えば、入力が a = 10、b = 15 の場合、出力は次のようになります。[3, 1, 4, 6, 2, 8, 5, 9, 10, 7]解法のアプローチこの問題は、再帰関数を使って配列を構築しながら、要素の入れ替えによってマージソートの呼び出し回数を調整することで解けます。手順は以下の通りです。再帰関数 solve(left, right, array, b) を定義します。b < 1 または区間の幅が1(

  2. Pythonで配列をパリティ(偶数・奇数)ごとに並べ替える方法

    問題の概要 いくつかの数値を含む配列 A が与えられたとします。この配列を、偶数が先頭に集まり、その後に奇数が続くように並べ替えます。 たとえば、配列が A = [1, 5, 6, 8, 7, 2, 3] の場合、期待される結果は [6, 8, 2, 1, 5, 7, 3] のようになります。 解法のアプローチ:2つのポインタを使う この問題は、いわゆる「2ポインタ法」と呼ばれるシンプルな手法で効率よく解けます。配列を一度だけ走査しながら、偶数を見つけるたびに配列の前方へ移動させていく考え方です。 具体的には、次の手順に従います。 インデックス i := 0 と j := 0 を初期化する