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

C++で最長ウィグル(振動)サブシーケンスの長さを求める方法

ウィグルシーケンスとは

隣り合う数値の差が正と負で厳密に交互に現れる数列を「ウィグルシーケンス」と呼びます。最初の差は正でも負でも構いません。また、要素が2つ未満の数列は自明にウィグルシーケンスとみなされます。

例えば [1,7,4,9,2,5] はウィグルシーケンスです。隣接する数値の差が (6, -3, 5, -7, 3) となり、正と負が交互に現れているためです。一方、[1,4,7,2,5] は最初の2つの差がどちらも正であるため、[1,7,4,5,5] は最後の差が0になってしまうため、それぞれウィグルシーケンスではありません。

問題の概要

整数列が与えられたとき、ウィグルシーケンスとなっている最長の部分列(サブシーケンス)の長さを求めます。部分列とは、元の数列からいくつかの要素(0個の場合も含む)を削除し、残りの要素を元の順序のまま保ったものです。

例えば入力が [1,7,4,9,2,5] の場合、数列全体がすでにウィグルシーケンスであるため、出力は6になります。

解法のアプローチ

この問題は動的計画法(DP)の考え方を使うことで、線形時間で効率的に解けます。手順は以下の通りです。

  • n を nums のサイズとします。
  • n が 0 の場合は 0 を返します。
  • up := 1、down := 1 と初期化します。up は「直前の差が正(上昇)で終わる最長ウィグル部分列」の長さ、down は「直前の差が負(下降)で終わる最長ウィグル部分列」の長さを表します。
  • i を 1 から n-1 まで繰り返します。
    • nums[i] > nums[i-1] の場合は up := down + 1 と更新します。
    • nums[i] < nums[i-1] の場合は down := up + 1 と更新します。
  • 最後に up と down の大きい方を返します。

このアルゴリズムの時間計算量は O(n)、追加のメモリ使用量は O(1) と非常に効率的です。等しい要素が続く場合は状態を更新しないため、重複値も正しく処理できます。

C++での実装例

以下の実装を見ると、理解がより深まるでしょう。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if(!n) return 0;
        int up = 1;
        int down = 1;
        for(int i = 1; i < n; i++){
            if(nums[i] > nums[i - 1]){
                up = down + 1;
            }
            else if(nums[i] < nums[i - 1]){
                down = up + 1;
            }
        }
        return max(up, down);
    }
};
main(){
    Solution ob;
    vector<int> v = {1,7,4,9,2,5};
    cout << (ob.wiggleMaxLength(v));
}

入力

[1,7,4,9,2,5]

出力

6
  1. C++でk番目の順列シーケンスを効率的に求める方法

    問題の概要 集合 [1, 2, 3, ..., n] には、合計 n! 通りの異なる順列が存在します。すべての順列を辞書順に並べてラベルを付けると、n = 3 の場合は次のシーケンスが得られます。 [123, 132, 213, 231, 312, 321] このとき、n と k が与えられた場合、k 番目の順列シーケンスを返すのが本問題の目的です。制約として、n は 1 以上 9 以下、k は 1 以上 n! 以下の範囲にあります。 アルゴリズムの考え方 すべての順列を生成して k 番目を探す方法は非効率です。そこで、階乗の性質を利用したアプローチを用います。 先頭の桁にどの数字を置くかを決

  2. 【C++】アリコット数列の求め方と実装例をわかりやすく解説

    アリコット数列とは アリコット数列(Aliquot Sequence)は、特殊な性質をもった数列です。数列はある整数から始まり、次の項は直前の項の真の約数(その数自身を除く約数)の総和として定義されます。 具体的な例で確認してみましょう。 入力 : 8 出力 : 8 7 1 0 解説 : 8 の真の約数は 4, 2, 1。その和は 7 7 の真の約数は 1。その和は 1 1 の真の約数は存在しないため、その和は 0 完全数・友愛数・社交数との関係 アリコット数列は、以下の3種類の特別な数と深い関わりがあります。 完全数:数列の長さが1(自分自身に戻る)となる数。例:6