簡體   English   中英

找到由兩個3位數字的乘積制成的最大回文

[英]Find the largest palindrome made from the product of two 3-digit numbers

package testing.project;

public class PalindromeThreeDigits {

    public static void main(String[] args) {
        int value = 0;
        for(int i = 100;i <=999;i++)
        {
            for(int j = i;j <=999;j++)
            {
                int value1 = i * j;
                StringBuilder sb1 = new StringBuilder(""+value1);
                String sb2 = ""+value1;
                sb1.reverse();
                if(sb2.equals(sb1.toString()) && value<value1) {
                    value = value1;

                }

            }
        }

        System.out.println(value);
    }
}

這是我用Java編寫的代碼......除此之外還有什么有效的方法..我們可以更優化這些代碼嗎?

我們假設最大的這樣的回文將有六位而不是五位,因為143 * 777 = 111111是回文。

如其他地方所述,6位數的10-palindrome abccba是11的倍數。這是正確的,因為* 100001 + b * 010010 + c * 001100等於11 * a * 9091 + 11 * b * 910 + 11 * C * 100。 因此,在我們的內循環中,如果m不是11的倍數,我們可以將n減少11步。

我們正試圖找到百萬以下最大的回文,這是兩個3位數字的乘積。 為了找到一個大的結果,我們首先嘗試大的除數:

  • 我們從999開始向下邁步,1;
  • 將n從999向下運行1(如果11除以m,或9%的時間)或從990除以11(如果11不除m,或91%的時間)。

我們追蹤到目前為止變量q中發現的最大回文。 假設q = r·s,r <= s。 我們通常有m <r <= s。 我們要求m·n> q或n> = q / m。 由於發現較大的回文,n的范圍受到更多限制,原因有兩個:q變大,m變小。

附加程序的內部循環僅執行506次,相對於所使用的朴素程序的~810000次。

#include <stdlib.h>
#include <stdio.h>
int main(void) {
  enum { A=100000, B=10000, C=1000, c=100, b=10, a=1, T=10 };
  int m, n, p, q=111111, r=143, s=777;
  int nDel, nLo, nHi, inner=0, n11=(999/11)*11;

  for (m=999; m>99; --m) {
    nHi = n11;  nDel = 11;
    if (m%11==0) {
      nHi = 999;  nDel = 1;
    }
    nLo = q/m-1;
    if (nLo < m) nLo = m-1;

    for (n=nHi; n>nLo; n -= nDel) {
      ++inner;
      // Check if p = product is a palindrome
      p = m * n;
      if (p%T==p/A && (p/B)%T==(p/b)%T && (p/C)%T==(p/c)%T) {
        q=p; r=m; s=n;
        printf ("%d at %d * %d\n", q, r, s);
        break;      // We're done with this value of m
      }
    }
  }
  printf ("Final result:  %d at %d * %d   inner=%d\n", q, r, s, inner);
  return 0;
}

注意,程序是在C中,但相同的技術將在Java中工作。

我會怎么做:

  1. 從999開始,向后退到998,997等
  2. 為我當前的號碼創建回文。
  3. 確定此數字的素數因子化(如果您有預先生成的素數列表,則不是那么昂貴。
  4. 通過此素數分解列表來確定我是否可以使用這些因子的組合來生成2個3位數字。

一些代碼:

int[] primes = new int[] {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,
73,79,83,89,97,101,103,107,109,113,,127,131,137,139,149,151,157,163,167,173,
179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,
283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,
419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,
547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,
661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,
811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,
947,953,967,971,977,983,991,997};

for(int i = 999; i >= 100; i--) {

    String palstr = String.valueOf(i) + (new StringBuilder().append(i).reverse());
    int pal = Integer.parseInt(pal);
    int[] factors = new int[20]; // cannot have more than 20 factors
    int remainder = pal;
    int facpos = 0;
    primeloop:
    for(int p = 0; p < primes.length; i++) {
        while(remainder % p == 0) {
            factors[facpos++] = p;
            remainder /= p;
            if(remainder < p) break primeloop;
        }
    }   
    // now to do the combinations here 
}

我們可以將任務翻譯成數學語言。

首先,我們使用字符作為數字:

abc * xyz = n 

abc is  a 3-digit number, and we deconstruct it as 100*a+10*b+c
xyz is  a 3-digit number, and we deconstruct it as 100*x+10*y+z

現在我們有兩個數學表達式,可以將a,b,c,x,y,z定義為{0..9}的€。
從{1..9}定義a和x作為元素更精確,而不是{0..9},因為097實際上不是一個3位數,是嗎?

好。

如果我們想要產生一個大數字,我們應該嘗試達到9 ......-數字,因為它應該是回文,它必須是9 ... 9的模式。 如果最后一個數字是9,那么從

(100*a + 10*b + c) * (100*x + 10*y + z) 

如果z * c必須導致一個數字,以數字9結尾 - 所有其他計算都不會感染最后一個數字。

所以c和z必須來自(1,3,7,9),因為(1 * 9 = 9,9 * 1 = 9,3 * 3 = 9,7 * 7 = 49)。

現在一些代碼(Scala):

val n = (0 to 9)
val m = n.tail // 1 to 9
val niners = Seq (1, 3, 7, 9)
val highs = for (a <- m;
  b <- n;
  c <- niners; 
  x <- m;
  y <- n;
  z <- niners) yield ((100*a + 10*b + c) * (100*x + 10*y + z))

然后我會按大小對它們進行排序,從最大的那個開始,測試它們是否為回文。 所以我會省略測試小數字的回文,因為這可能不那么便宜。

出於美學原因,我不會采用(toString.reverse == toString)方法,而是遞歸除法和模解決方案,但在今天的機器上,它沒有太大的區別,是嗎?

// Make a list of digits from a number: 
def digitize (z: Int, nums : List[Int] = Nil) : List[Int] =
  if (z == 0) nums else digitize (z/10, z%10 :: nums)

/* for 342243, test 3...==...3 and then 4224. 
   Fails early for 123329 */
def palindromic (nums : List[Int]) : Boolean = nums match {
  case Nil           => true 
  case x :: Nil      => true 
  case x :: y :: Nil => x == y 
  case x :: xs       => x == xs.last && palindromic (xs.init) }

def palindrom (z: Int) = palindromic (digitize (z))

出於嚴格的性能考慮,我將針對toString / reverse / equals方法進行測試。 也許情況更糟。 它應該盡早失敗,但是不知道除法和模數是最快的操作,我用它們從Int創建一個List。 它適用於BigInt或Long,幾乎沒有重新聲明,並且適用於Java; 可以用Java實現,但在那里看起來不同。

好吧,把事情放在一起:

highs.filter (_ > 900000) .sortWith (_ > _) find (palindrom) 
res45: Option[Int] = Some(906609)

那里有835個數字> 900000,並且它返回的速度相當快,但我想更強大的蠻力也不會慢得多。

也許有一種更聰明的方法來構建最高的palindrom,而不是搜索它。

一個問題是:我以前不知道,有一個解決方案> 900000。


一種非常不同的方法是產生大的回文,並解構它們的因素。

public class Pin
{
    public static boolean isPalin(int num)
    {
        char[] val = (""+num).toCharArray();
        for(int i=0;i<val.length;i++)
        {
            if(val[i] != val[val.length - i - 1])
            {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args)
    {
        for(int i=999;i>100;i--)
            for(int j=999;j>100;j--)
            {
                int mul = j*i;
                if(isPalin(mul))
                {
                    System.out.printf("%d * %d = %d",i,j,mul);
                    return;
                }
            }
    }
}
 package ex;

    public class Main {

        public static void main(String[] args) {
            int i = 0, j = 0, k = 0, l = 0, m = 0, n = 0, flag = 0;

            for (i = 999; i >= 100; i--) {
                for (j = i; j >= 100; j--) {
                    k = i * j;

                    // System.out.println(k);
                    m = 0;
                    n = k;

                    while (n > 0) {
                        l = n % 10;
                        m = m * 10 + l;
                        n = n / 10;
                    }

                    if (m == k) {
                        System.out.println("pal " + k + " of " + i + " and" + j);
                        flag = 1;
                        break;
                    }
                }

                if (flag == 1) {
                    // System.out.println(k);
                    break;
                }
            }
        }
    }   

一種稍微不同的方法,可以輕松計算最多兩個6位數字的乘積所產生的最大回文數。

第一部分是創建回文數的發生器。 所以沒有必要檢查一個數字是否是回文,第二部分是一個簡單的循環。

#include <memory>
#include <iostream>
#include <cmath>

using namespace std;
template <int N>
class PalindromeGenerator {
    unique_ptr <int []> m_data;
    bool m_hasnext;
public :
    PalindromeGenerator():m_data(new int[N])
    {
        for(auto i=0;i<N;i++)
        m_data[i]=9;
        m_hasnext=true;
   }
  bool hasNext() const {return m_hasnext;}

long long int getnext()
{
    long long int v=0;
    long long int b=1;
    for(int i=0;i<N;i++){
        v+=m_data[i]*b;
        b*=10;
    }
    for(int i=N-1;i>=0;i--){
        v+=m_data[i]*b;
        b*=10;
    }

    auto i=N-1;
    while (i>=0)
    {
        if(m_data[i]>=1) {
            m_data[i]--;
            return v;
        }
        else 
        {
            m_data[i]=9;
           i--; 
        }
    }

    m_hasnext=false;
    return v;
}


};

template<int N>
void findmaxPalindrome()
{
    PalindromeGenerator<N> gen;
    decltype(gen.getnext()) minv=static_cast<decltype(gen.getnext())> (pow(10,N-1));
    decltype(gen.getnext()) maxv=static_cast<decltype(gen.getnext())> (pow(10,N)-1);
    decltype(gen.getnext()) start=11*(maxv/11);
    while(gen.hasNext())
    {
        auto v=gen.getnext();
        for (decltype(gen.getnext())  i=start;i>minv;i-=11)
        {
            if (v%i==0)
            {
                auto r=v/i;
                if (r>minv && r<maxv ){
                    cout<<"done:"<<v<<" "<<i<< "," <<r <<endl;
                    return ;
                }
            }

      }
    }

return ;
}
int main(int argc, char* argv[])
{
    findmaxPalindrome<6>();
    return 0;
}
i did this my way , but m not sure if this is the most efficient way of doing this .

package problems;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


  public class P_4 {

/**
 * @param args
 * @throws IOException 
 */
static int[] arry = new int[6];
static int[] arry2 = new int[6];

public static boolean chk()
{
    for(int a=0;a<arry.length;a++)
        if(arry[a]!=arry2[a])
            return false;

return true;

}

public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub

    InputStreamReader ir = new InputStreamReader(System.in);
    BufferedReader br = new BufferedReader(ir);
    int temp,z,i;

for(int x=999;x>100;x--)
    for(int y=999;y>100;y--)
        {
        i=0;
            z=x*y;
            while(z>0)
                {
                    temp=z%10;
                    z=z/10;
                    arry[i]=temp;
                    i++;
                }

            for(int k = arry.length;k>0;k--)
                        arry2[arry.length- k]=arry[k-1];

    if(chk())
    {
        System.out.print("pelindrome = ");

for(int l=0;l<arry2.length;l++)
System.out.print(arry2[l]);
System.out.println(x);
System.out.println(y);
}

    }
}
}

這是C中的代碼,有點長,但是完成了工作。:)

#include <stdio.h>
#include <stdlib.h>
/*
A palindromic number reads the same both ways. The largest palindrome made from the                                 product of two
2-digit numbers is 9009 = 91  99.

Find the largest palindrome made from the product of two 3-digit numbers.*/

int palndr(int b)
{
int *x,*y,i=0,j=0,br=0;
int n;
n=b;
while(b!=0)
{
   br++;
   b/=10;
}
x=(int *)malloc(br*sizeof(int));
y=(int *)malloc(br*sizeof(int));

int br1=br;

while(n!=0)
{
    x[i++]=y[--br]=n%10;
    n/=10;
}

int ind = 1;
for(i=0;i<br1;i++)
if(x[i]!=y[i])
ind=0;
free(x);
free(y);
return ind;
}

int main()
{
   int i,cek,cekmax=1;
   int j;
   for(i=100;i<=999;i++)
   {
       for(j=i;j<=999;j++)
        {
        cek=i*j;

       if(palndr(cek))
        {
            if(pp>cekmax)
            cekmax=cek;
        }
        }
   }

   printf("The largest palindrome is: %d\n\a",cekmax);
}

你可以用Python實際做到這一點,它很容易看看:

actualProduct = 0
highestPalindrome = 0

# Setting the numbers. In case it's two digit 10 and 99, in case is three digit 100 and 999, etc.
num1 = 100
num2 = 999

def isPalindrome(number):
        number = str(number)
        reversed = number[::-1]
        if number==reversed:
                return True
        else:
                return False

a = 0
b = 0

for i in range(num1,num2+1):
        for j in range(num1,num2+1):
                actualProduct = i * j
                if (isPalindrome(actualProduct) and (highestPalindrome < actualProduct)):
                        highestPalindrome = actualProduct
                        a = i
                        b = j


print "Largest palindrome made from the product of two %d-digit numbers is [ %d ] made of %d * %d" % (len(str(num1)), highestPalindrome, a, b)

由於我們沒有同時循環使用迭代器(num1和num2),因此我們找到的第一個回文數將是最大的。 我們不需要測試我們發現的回文是否是最大的。 這大大減少了計算所需的時間。

package testing.project;
public class PalindromeThreeDigits {
    public static void main(String[] args) {

    int limit = 99;
    int max = 999;
    int num1 = max, num2, prod;

    while(num1 > limit)
    {
        num2 = num1;
        while(num2 > limit)
        {
            total = num1 * num2;
            StringBuilder sb1 = new StringBuilder(""+prod);
            String sb2 = ""+prod;
            sb1.reverse();
            if( sb2.equals(sb1.toString()) ) {    //optimized here
                //print and exit
            }
            num2--;
        }
        num1--;
    }

 }//end of main
 }//end of class PalindromeThreeDigits

我嘗試了Tobin joy和vickyhacks的解決方案,他們兩個都產生了結果580085這是錯的,這是我的解決方案,雖然非常笨拙:

import java.util.*;
class ProjEu4
{

public static void main(String [] args) throws Exception
{
    int n=997;
    ArrayList<Integer> al=new ArrayList<Integer>();
    outerloop:
    while(n>100){
    int k=reverse(n);
    int fin=n*1000+k;
            al=findfactors(fin);
    if(al.size()>=2)
        {
            for(int i=0;i<al.size();i++)
            {
                if(al.contains(fin/al.get(i))){
                    System.out.println(fin+" factors are:"+al.get(i)+","+fin/al.get(i));
                    break outerloop;}
            }

        }
        n--;
    }
}
private static ArrayList<Integer> findfactors(int fin)
{
    ArrayList<Integer> al=new ArrayList<Integer>();
    for(int i=100;i<=999;i++)
    {
        if(fin%i==0)
            al.add(i);
    }
    return al;
}
private static int reverse(int number)
{
    int reverse = 0;
    while(number != 0){
        reverse = (reverse*10)+(number%10);
        number = number/10;
    }
    return reverse;
}
}

最有可能的是復制其他解決方案之一但由於pythonified代碼它看起來很簡單,即使它有點蠻力。

def largest_palindrome():
    largest_palindrome = 0;
    for i in reversed(range(1,1000,1)):
        for j in reversed(range(1, i+1, 1)):
            num = i*j
            if check_palindrome(str(num)) and  num > largest_palindrome :
                largest_palindrome = num 
    print "largest palindrome ", largest_palindrome

def check_palindrome(term):
    rev_term = term[::-1]
    return rev_term == term

怎么樣:在python中

>>> for i in range((999*999),(100*100), -1):
...     if str(i) == str(i)[::-1]:
...         print i
...         break
...
997799
>>>

我相信有一種更簡單的方法:檢查從兩位三位數的最大乘積下降的回文,選擇具有兩個三位數因子的第一個回文。

這是Ruby代碼:

require './palindrome_range'
require './prime'

def get_3_digit_factors(n)
  prime_factors = Prime.factors(n)

  rf = [prime_factors.pop]
  rf << prime_factors.shift while rf.inject(:*) < 100 || prime_factors.inject(:*) > 999

  lf = prime_factors.inject(:*)
  rf = rf.inject(:*)

  lf < 100 || lf > 999 || rf < 100 || rf > 999 ? [] : [lf, rf]
end

def has_3_digit_factors(n)
  return !get_3_digit_factors(n).empty?
end

pr = PalindromeRange.new(0, 999 * 999)
n = pr.downto.find {|n| has_3_digit_factors(n)}
puts "Found #{n} - Factors #{get_3_digit_factors(n).inspect}, #{Prime.factors(n).inspect}"

prime.rb:

class Prime

  class<<self

    # Collect all prime factors
    # -- Primes greater than 3 follow the form of (6n +/- 1)
    #    Being of the form 6n +/- 1 does not mean it is prime, but all primes have that form
    #    See http://primes.utm.edu/notes/faq/six.html
    # -- The algorithm works because, while it will attempt non-prime values (e.g., (6 *4) + 1 == 25),
    #    they will fail since the earlier repeated division (e.g., by 5) means the non-prime will fail.
    #    Put another way, after repeatedly dividing by a known prime, the remainder is itself a prime
    #    factor or a multiple of a prime factor not yet tried (e.g., greater than 5).
    def factors(n)
      square_root = Math.sqrt(n).ceil
      factors = []

      while n % 2 == 0
        factors << 2
        n /= 2
      end

      while n % 3 == 0
        factors << 3
        n /= 3
      end

      i = 6
      while i < square_root
        [(i - 1), (i + 1)].each do |f|
          while n % f == 0
            factors << f
            n /= f
          end
        end

        i += 6
      end

      factors << n unless n == 1
      factors
    end

  end

end

palindrome_range.rb:

class PalindromeRange

  FIXNUM_MAX = (2**(0.size * 8 -2) -1)

  def initialize(min = 0, max = FIXNUM_MAX)
    @min = min
    @max = max
  end

  def downto
    return enum_for(:downto) unless block_given?

    n = @max
    while n >= @min
      yield n if is_palindrome(n)
      n -= 1
    end
    nil
  end

  def each
    return upto
  end

  def upto
    return enum_for(:downto) unless block_given?

    n = @min
    while n <= @max
      yield n if is_palindrome(n)
      n += 1
    end
    nil
  end

  private

  def is_palindrome(n)
    s = n.to_s
    i = 0
    j = s.length - 1
    while i <= j
      break if s[i] != s[j]
      i += 1
      j -= 1
    end
    i > j
  end

end
public class ProjectEuler4 {

public static void main(String[] args) {

    int x = 999; // largest 3-digit number
    int largestProduct = 0;

    for(int y=x; y>99; y--){
        int product = x*y;

        if(isPalindormic(x*y)){
            if(product>largestProduct){
                largestProduct = product;
                System.out.println("3-digit numbers product palindormic number : " + x + " * " + y + " : " + product);
            }
        }

        if(y==100 || product < largestProduct){y=x;x--;}
    }


}

public static boolean isPalindormic(int n){

    int palindormic = n;
    int reverse = 0;

    while(n>9){
        reverse = (reverse*10) + n%10;
        n=n/10;
    }
    reverse = (reverse*10) + n;     
    return (reverse == palindormic);
}
}

您可以使用11是回文的倍數來減少搜索空間的事實。 我們可以得到這個,因為我們可以假設回文將是6位數並且> = 111111。

例如(來自projecteuler;))

P= xyzzyx = 100000x + 10000y + 1000z + 100z + 10y +x
P=100001x+10010y+1100z
P=11(9091x+910y+100z)

檢查i mod 11!= 0,然后j循環可以減去11(從990開始),因為兩者中的至少一個必須可被11整除。

您可以嘗試以下打印

999 * 979 * 989 = 967262769
largest palindrome= 967262769 took 0.015

public static void main(String... args) throws IOException, ParseException {
  long start = System.nanoTime();
  int largestPalindrome = 0;
  for (int i = 999; i > 100; i--) {
    LOOP:
    for (int j = i; j > 100; j--) {
      for (int k = j; k > 100; k++) {
        int n = i * j * k;
        if (n < largestPalindrome) continue LOOP;
        if (isPalindrome(n)) {
          System.out.println(i + " * " + j + " * " + k + " = " + n);
          largestPalindrome = n;
        }
      }
    }
  }
  long time = System.nanoTime() - start;
  System.out.printf("largest palindrome= %d took %.3f seconds%n", largestPalindrome, time / 1e9);
}

private static boolean isPalindrome(int n) {
  if (n >= 100 * 1000 * 1000) {
    // 9 digits
    return n % 10 == n / (100 * 1000 * 1000)
        && (n / 10 % 10) == (n / (10 * 1000 * 1000) % 10)
        && (n / 100 % 10) == (n / (1000 * 1000) % 10)
        && (n / 1000 % 10) == (n / (100 * 1000) % 10);
  } else if (n >= 10 * 1000 * 1000) {
    // 8 digits
    return n % 10 == n / (10 * 1000 * 1000)
        && (n / 10 % 10) == (n / (1000 * 1000) % 10)
        && (n / 100 % 10) == (n / (100 * 1000) % 10)
        && (n / 1000 % 10) == (n / (10 * 1000) % 10);
  } else if (n >= 1000 * 1000) {
    // 7 digits
    return n % 10 == n / (1000 * 1000)
        && (n / 10 % 10) == (n / (100 * 1000) % 10)
        && (n / 100 % 10) == (n / (10 * 1000) % 10);
  } else throw new AssertionError();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM