揺palindromic製品の問題
-
27-09-2019 - |
質問
って学習Rubyいう私のプロジェクトオイラーパズルを解いたりしています。Embarrassinglyだけでも問題4...
課題4のものとなっていおり
A palindromic数を読み込みと同じ 両です。最大回文を作 製品からの2桁 数9009=91×99.
の最大の回文から 製品の3桁の番号
うきっかけになるかもしれないというループから999 100入れ子ループ、試験の回文としてのループを発見したときには最初にある最大):
final=nil
range = 100...1000
for a in range.to_a.reverse do
for b in range.to_a.reverse do
c=a*b
final=c if c.to_s == c.to_s.reverse
break if !final.nil?
end
break if !final.nil?
end
puts final
これは、出力回文580085るのだそうなのがこの最高の製品の三桁の数字内いて、幅で示したものである。奇妙に、同じコードが成功するに戻9009のような例の場合、変更したい範囲は10---100です。
- で誰か教えてくるん 間違いだったのか?
- もあるのでお勧め の内部ループ?
感謝
解決
あなたは999 *(999 ... 100)、次に998 *(999 ... 100)をテストしています
したがって、997 * 996をテストする前に999 * 500をテストします。
それで、どうやってその正しい数を見つけるのですか?
まず、乗算は反射的であるため、a * b == b * aなので、bは999 ... 0から毎回行く必要はありません。
Palindroneを見つけたら、2つの要因を一緒に追加して合計を保存します(2つの要因も保存します)
ループ内で、(a+b)が保存された合計よりも少ない場合、内側のループを放棄し、次のaに移動します。 sum/2を下回ると、見つけた将来の価値は、すでに見つけた将来の価値よりも高くないので、完了です。
他のヒント
問題は、あなたがパリンドロームを見つけるかもしれないということです a
999とa b
200人ですが、早すぎるので、998*997(例の例のみ)に1つあることがわかりません。
すべてのパリンドロムを探すか、最初のパリンドロームを見つけたら、それを設定する必要があります b
最小限のバウンドとして、そしてそれを調べ続けます a
ループ。
2番目の質問に関しては、私のアドバイスは、手続き的な方法よりも、より機能的に問題にアプローチすることです。したがって、ループするのではなく、問題を機能的に「説明」しようとすることができ、Rubyに仕事をさせてください。
- 3桁の数字のすべてのペアから、
select
製品がパリンドロームである人だけ、- そして、最大の製品を持つものを見つけます
このアプローチは、最も効率的なソリューションを生み出すことはないかもしれませんが、いくつかのRuby Idiomsを教えるかもしれません。
pの数字を考えてみましょう - それらをx、y、zとします。 Pは、Palindrome 111111 = 143×777であるため、少なくとも6桁でなければなりません。2つの3桁の整数の積。 pはパリンドロームであるため:
P=100000x + 10000y + 1000z + 100z + 10y + x
P=100001x + 10010y + 1100z
P=11(9091x + 910y + 100z)
11はプライムなので、整数aまたはbの少なくとも1つは11の係数を持っている必要があります。したがって、Aが11で割り切れない場合、bはbでなければならないことを知っています。この情報を使用して、aに応じてチェックするbの値を決定できます。
C#実装:
using System;
namespace HighestPalindrome
{
class Program
{
static void Main(string[] args)
{
int i, j;
int m = 1;
bool flag = false;
while (true)
{
if (flag) j = m + 1;
else j = m;
for (i = m; i > 0; i--)
{
Console.WriteLine("{0} * {1} = {2}", 1000 - i, 1000 - j, (1000 - i) * (1000 - j));
j++;
//--- Palindrome Check ------------------------------
int number, temp, remainder, sum = 0;
number = temp = (1000 - i) * (1000 - j);
while (number > 0)
{
remainder = number % 10;
number /= 10;
sum = sum * 10 + remainder;
}
if (sum == temp)
{
Console.WriteLine("Highest Palindrome Number is - {0} * {1} = {2}", 1000 - i, 1000 - j, temp);
Console.ReadKey();
return;
}
//---------------------------------------------------
}
if (flag)
m++;
flag = !flag;
}
}
}
}
の間違いはあるだpalindromが最も大きい a
値で最大の製品でちょっと違うんです。値段が高くなりますが、保 max_product
値作成-更新するとともに防液ます。
私はあなたの最初の質問に答えることができます:あなたは最高の要因を含む製品ではなく、最高の製品を見つける必要があります。言い換えると a * b
より大きくなる可能性があります c * d
もしそれでも c > a > b
.
あなたが来た最初のパリンドロームで壊れているのは、必ずしも最大ではありません。
a、b、c、d、eがあるとします。 e * aをテストする前にd * Cをテストする
ar=[]
limit = 100..999
for a in limit.to_a.reverse do
for b in (100..a).to_a.reverse do
c=a*b
if c.to_s == c.to_s.reverse
palndrm=c
ar << palndrm
end
end
end
print ar
print"\n"
puts ar.max
puts ar.min
実装:
max = 100.upto(999).inject([-1,0,0]) do |m, a|
a.upto(999) do |b|
prod = a * b
m = [prod, a, b] if prod.to_s == prod.to_s.reverse and prod > m[0]
end
m
end
puts "%d = %d * %d" % max
プリント 906609 = 913 * 993
主なことは、考えられるすべての値を通過することです。最初の答えがゼロのベストアンサーから始めて、すべての組み合わせを試して最善を尽くしてください。二次的なことは、「すべての組み合わせ」のセットを削減しようとすることです。
あなたができることの1つは、あなたの内側ループをA以下の値に制限することです(b == ba)。これにより、方程式の値が常にAに大きくなり、テストする必要がある値の数が大幅に減少します。
for a in range.to_a.reverse do
for b in (100..a).to_a.reverse do
次にできることは、製品が現在の最高の値よりも小さいときはいつでも、内側のループから抜け出すことです。
c = a*b
next if c < best
次に、とにかくすべてを通過する場合は、逆にそれらを通過することに利点はありません。範囲の上部から始めることで、パリンドローム数を見つけるまでに時間がかかり、その結果、検索セットを削減するのに時間がかかります。下から始めれば、下限をすばやく増やし始めます。
for a in range.to_a do
for b in (100..a).to_a do
私のテストでは、いずれにせよ、405kペアを試してみることがわかります。それで、問題を別の方法で考えるのはどうですか。 2つの3桁の数字の最大の製品は何ですか? 999*999 = 998001と最小は100*100 = 10000です。最初の答えを破ったが、それを別の範囲に適用するというアイデアを取得してください。 100)。
for c in (10000...998001).to_a.reverse do
わずか202のテストの後にパリンドロームに到達します...問題は、2つの3桁の数字の産物ではないことです。したがって、私たちが見つけたパリンドロームが2つの3桁の数値の製品であるかどうかを確認する必要があります。パリンドロームと2つの3桁の数字の製品である範囲の値を見つけたらすぐに。私のテストでは、93K未満のテスト後に要件を満たす最高のパリンドロームを見つけます。しかし、その時点までのすべてのパリンドロムが2つの3桁の数字の積であることをチェックするオーバーヘッドがあるため、以前のソリューションよりも効率的ではないかもしれません。
元の改善に戻りましょう。
for a in range.to_a.reverse do
for b in (100..a).to_a.reverse do
列をループし、列をループし、現在の行の追加トリは現在の最高よりも優れていない可能性があるため、次の行に行くことができるポイントを検出することで効率的にしようとしています。行を下る代わりに、対角線を横切る場合はどうなりますか?
製品は対角線によってより小さく斜めになるため、パリンドーム番号を見つけるとすぐに停止できます。これは非常に効率的なソリューションですが、より複雑な実装があります。この方法では、2200トリをわずかに超えた後、最高のパリンドロームが見つかります。
これが私がRubyで思いついたものです:
def largest_palindrome_product(digits)
largest, upper, lower = 0, 10**digits - 1, 10**(digits - 1)
for i in upper.downto(lower) do
for j in i.downto(lower) do
product = i * j
largest = product if product > largest && palindrome?(product)
end
end
largest
end
そして、これが数字がパリンドロームであるかどうかを確認する機能です:
def palindrome?(input)
chars = input.to_s.chars
for i in 0..(chars.size - 1) do
return false if chars[i] != chars[chars.size - i - 1]
end
true
end
ただし、おそらくより効率的なソリューションがあると思います。
この問題については、最高のパリンドロムを探しているので、私はそれが9で始まると思いました。
注意を払うと、9つに終了する数字を取得するには、9と1、3と3、7、7、7、7、7での数字のみを取得できます。
その後、他の値を確認することは役に立たない(たとえば、999*998は9で終わらないため)。
999と991から始めると、999と981などを試して10から991を覆すことができます... 993と993で同じことをします... 997 * 997 TON 997 * 987などで同じ最高が以前になることを確認できるので、900または10^4-10^3を超える必要があります。
int PB4_firstTry(int size)
{
int nb1 = (int)pow(10.0,size+1.0) - 1, nb2 = (int)pow(10.0,size+1.0) - 1;
int pal91 = getFirstPalindrome(size,9,1);
int pal33 = getFirstPalindrome(size,3,3);
int pal77 = getFirstPalindrome(size,7,7);
int bigger1 = (pal91 > pal33) ? pal91 : pal33;
return (bigger1 > pal77) ? bigger1 : pal77;
}
int getFirstPalindrome(int size,int ending1,int ending2)
{
int st1 = (int)pow(10.0,size+1.0) - 10 + ending1;
int comp = st1 - pow(10.0,size);
int st2 = (int)pow(10.0,size+1.0) - 10 + ending2;
int answer = -1;
while (st1 > comp)
{
for (int i = st2; i > comp && st1*i > answer; i-=10)
{
if (PB4_isPalindrome(st1*i))
answer = st1*i;
}
st1 -= 10;
}
return answer;
}
bool PB4_isPalindrome(int number)
{
std::string str = intToString(number);
for (int i = 0; i < (int)(str.length() / 2); i++)
{
if (str[i] != str[str.length() - 1 - i])
return false;
}
return true;
}
std::string intToString(int number)
{
std::ostringstream convert;
convert << number;
return convert.str();
}
もちろん、これは4サイズの桁の要因などで機能します。