学校に戻る:質問7-264。醜い数字II(独創的な動的計画法のアイデア)

264.醜い数II

n番目の醜い数を見つけるプログラムを書いてください。

醜い数は正の整数であり、その素因数には2、3、および5しか含まれていません。

示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:  

1 是丑数。
n 不超过1690。

回答:

方法1:暴力

つまり、醜い数の性質を「判断」として使用して問題を解決するため、数が醜い数であるかどうかを確認する方法をコードに書き留めてから、醜い数を格納する配列を追加するだけで済みます。毎回醜い数字が全部になったら最後の醜い数字を見つけたら出力できますが、この方法では2から始まる数字をすべて検証する必要があり、非常に複雑で時間がなくなります。

コード:

int nthUglyNumber(int n){
    
    
    int temp = 2;//用来储存最后一个丑数
    int sum = 1;
    while(sum!=n)//丑数不到n个就一直循环
    {
    
    
        int num = temp;//需要个中间量来完成丑数的验证过程
        while(num!=1)
        {
    
    
            if(num%2==0)
            {
    
    
                num=num/2;
                continue;
            }
            else if(num%3==0)
            {
    
    
                num=num/3;
                continue;
            }
            else if(num%5==0)
            {
    
    
                num=num/5;
                continue;
            }
            else
            {
    
    
                goto A;
            }
        }
        sum++;
        A:temp++;
    }
    return temp-1;
}

方法2:3つのポインター+動的計画法

この方法は、論理的思考と推論逆転させる能力をテストします。私たちの目標はn番目の醜い番号を見つけることなので、この場合、方法1のようにすべての番号を検索するのではなく、醜い番号から1つずつ直接見つけることできますか?次に、この数がコードの醜い部分の数であることを確認するために省略できることがわかります。これは、数が醜い数であるかどうかを確認するためではないためです。

次に、見つけたすべての数字を醜い数字にする方法を考えますか?
もう一度質問を読んで、醜い数の性質は素因数が2、3、5であるということだけであることがわかります。
次に、最初に与えられた醜い数1については、任意の数2、任意の数3、および任意の数5を掛けますが、それでも醜い数です。高度な醜い数2、3、および5については、彼が任意の数の2、任意の数の3、任意の数の5を乗算した後、彼はまだ醜い数です...

したがって、数値を探すときに2つの数値間のスパンを調整するだけでよいことがわかりました。

方法1では、すべての番号を検索したため、スパンは1であり、ここでスパンを変更するだけで済みます。
しかし、どうすれば醜い数字を見逃すことはできませんか?それを直接探して、それが一つであることがわかると、私たちの思考を混乱させるでしょう。したがって、検索基準定式化する必要があります。つまり、小さいものから大きいものへと検索ます。

ここでは、 3つのポインターと動的計画法を使用して、上記の説明プロセスを完了します。

まず、上記の知識があるため、次の醜い数を計算するときの計算量を減らすために、前の醜い数のサイズデータ、つまり対応する2、3を直接乗算する必要があります。 5以前の醜い数に基づいて、私たちが望むものをより速く達成します。醜い数そのため、見つけた醜い数字を小さいものから大きいものへと並べ替えて格納する配列を作成できます。

次に、乗算する2、3、および5の数に対応する3つのポインターを設定し(コード内の対応する数は-1)、ループ、つまり、醜いものが見つからないループに入ります。数字は出られません。

小さいものから大きいものへの醜い数の検索を満たすために、醜い数1に基づいて2、3、5の数を掛けることによって形成される最小の醜い数を見つける最小の関数を作成し、それを配列に入れます彼それを見つけた後、それを変更します。彼はポインタの位置(つまり、それらが乗算する2、3、5の数値)に対応し、次のサイクルに入ります。
動的計画法自体はいわゆる「戻る」=「前」または「前」=「後」のプロセスであるため、ポインターが変更されたため、次に最小の比較が使用されるときに、比較も変わります。

コード:

//新思路:三指针法,第一个丑数设为1,接着不断用235乘以它们指针所在的位置,比较谁小的方法,如果采用某一指针,则指针进一;
int least(int x,int y,int z)
{
    
    
    int temp = x<y?x:y;
    return temp<z?temp:z;
}
int nthUglyNumber(int n){
    
    
    int*nums=(int*)malloc(sizeof(int)*n);
    nums[0]=1;
    int p = 0;
    int q = 0;
    int m = 0;
    for(int i=1;i<n;i++)
    {
    
    
        nums[i]=least(nums[p]*2,nums[q]*3,nums[m]*5);//这里其实就是我们日常遇到的动态规划的过程,即“后”=“前”
        if(nums[i]==nums[p]*2)
        {
    
    
            p++;
        }
        if(nums[i]==nums[q]*3)
        {
    
    
            q++;
        }
        if(nums[i]==nums[m]*5)
        {
    
    
            m++;
        }
    }
    return nums[n-1];
}

おすすめ

転載: blog.csdn.net/xiangguang_fight/article/details/114544189