views:

348

answers:

2

Hi,

I'm trying to solve problem 32 of project euler in Java but I'm not getting the correct answer. I'm getting the answer of the following program as 48146. Could anyone please tell me what's wrong I'm doing here and how can I solve that problem?

Here's the code through which I'm trying to solve that problem:

public class Euler32
{

   public static boolean checkValue(char c,String s,int j)
   {   

       for(int i=j+1;i<s.length();i++)
     if(c==s.charAt(i)) return true;

  return false;
 } 



 public static void main(String[] args)
 {
long total=0;
long sum=0;

  for(int i1=40;i1<=999;i1++)
  {   
      for(int j=130;j<=9999;j++)
      {

       sum=i1*j;
       String s=i1+""+j+""+sum;

       if(s.length()!=9) continue;


      else
         {
          for(int i=0;i<s.length()-1;i++)
         {


        if(checkValue(s.charAt(i),s,i))
        break;

     if(i+1==s.length()-1) total+=sum;


         }
      } 
        }
    }
 System.out.println("Total sum is: "+total);
  }  



 }
A: 

You are missing some points:

  1. It is 1..9
  2. Unique products
  3. How comes you use 40 and 130(just curious)

(remember, understanding the problem solves 50% of it)

Recommendations:

  1. Learn about continue [label]; statement and use a local for loop instead of checkValue
  2. Why use s.length() more than once?
  3. Use StringBuilder
Marius Burz
+1  A: 

ok, few notes:

  1. Your assumption to start from 40 is incorrect, since 4*1783=6952 is pandigital. And there is another one you are missing :)
  2. You are not excluding duplicate products.

Based on the discussion with Marius, im updating the original answer, here. This is the isPandigital method only.

private boolean isPandigital(int a,int b){
   int c=a*b;
   StringBuilder st =  new StringBuilder();
   st.append(a).append(b).append(c);

   if (st.length()!=9 || st.indexOf("0")>-1) return false;

   Set<Character> x=new TreeSet<Character>();

   for (int i=0;i<9; i++){
       x.add(st.charAt(i));
   }
  if (x.size()==9){
     for (int k=0;k<=cnt;k++){
        if (products[k]==c) return false;
     }
  products[++cnt]=c;
  total += c;

  return true;
  }
 return false;
}

I compared both codes on my machine, ten tries then average, the results are as follows:

  1. Marius code: average (2070ms)
  2. medopal code: average (2200ms)
  3. Marius code (using String): average (4200ms)
  4. medopal code (using String): average (5000ms)

I added the String vs StringBuilder comparison because apperantly it was the thing that made my original code so slow. But using StringBuilder, Marius code beats me in average 200ms only :)

Lessons learned:

  • StringBuilder takes almost half the time String does. (in this experiment at least)
  • When you are lazy to think, you can use ready structures. (again in this experiment at least), im not generalizing

Thanks Marius :)

medopal
Set/TreeSet is actually slower than a local well crafted for loop(instead of the function).
Marius Burz
Its just a small quick application, the TreeSet is O(log N), I'm not sure i can do a Pandigital check in one for loop, except if I add another structure like an Array or List with IFs. So i chose the short path :), Thanks for the note anyway.
medopal
How do you add the entries to the Set? The note can be changed, just argue your point.
Marius Burz
Its a simple isPandigital method, this is my laziest implementation.I loop over the 9 characters string, parse and add each one to the set. for (char c:string.toCharArray()) {set.add(parse(c);} at the end return set.size()==9;
medopal
I believe you need some more, you must check for zeros. Since you already have a loop, I completely miss on your above point "I'm not sure i can do a Pandigital check in one for loop".
Marius Burz
before the loop there is one IF, i didnt write because it wasnt the point, its checks if length==9 and str.indexOf("0")<0.About the one "For loop", i meant i couldnt think if a simple For Loop to check if a number is pandigital. so if we use two nested for loops, i believe it would become slower than the Set. no?
medopal
Well, I doubt you have less than 2 loops this way ;) For once, indexOf needs a loop. As about the performance, it depends on how you write your nested loops. As about Set, why would you think it's faster? Have you actually tested? Would you think that just by writing more lines of code, your code will become slower?
Marius Burz
I didnt test the performance, but while thinking quickly, i concluded that if i will use one For loop, i will need to use an Array or List to store the chars, then check at end. Anyway, give me just 5 minutes, i will do a nested For loop and compare with the TreeSet. will be back
medopal
ok, im back, i made two for loops, in the first loop i get the character at current index, start the nested loop from currentindex+1, and loop, if the number at current index matches any number in the nested loop then return false.So the result is, the SET is faster, both methods are testing 10 million numbers, where there is 16 Pandigitals. The Set method takes around 5000 milli-seconds. The nested loop takes around 6500 milliseconds. If you have a better implementation dont hesitatem we are here to learn :), i just proved to myself, laziness is useful sometimes ;-)
medopal
My nested loops method only takes 1150ms(according to the profiler), I'm gonna post my code in my answer. Please also post your code with Set.
Marius Burz
Will add a new answer
medopal
Confirming what Marius said, those two methods might seem good, but a mathematical solution will be much more faster than Brute Force.
medopal