Skip to content

Instantly share code, notes, and snippets.

@phaniram
Created January 26, 2012 11:47
Show Gist options
  • Save phaniram/1682408 to your computer and use it in GitHub Desktop.
Save phaniram/1682408 to your computer and use it in GitHub Desktop.
Interview Street Challenges - Lucky Numbers
package interviewstreet;
import java.util.Scanner;
public class lucky_num {
public static void main(String[] args) {
lucky_num sr = new lucky_num();
Scanner scanner = new Scanner(System.in);
int no_cases = scanner.nextInt();
for (int i = 0; i < no_cases; i++) {
System.out.println(sr.solve(scanner.nextLong(), scanner.nextLong()));
}
}
private int solve(long l, long m) {
int count = 0;
for (long i = l; i <= m; i++) {
if (logic(i)) {
count++;
}
}
return count;
}
private boolean logic(long i) {
return (isSUM(i) && isSUMsq(i));
}
private boolean isSUMsq(long i) {
int sum = 0;
while (i > 9) {
long k = i % 10;
i = i / 10;
sum += k * k;
}
sum += i * i;
return (isPrime(sum));
}
private boolean isSUM(long i) {
int sum = 0;
while (i > 9) {
long k = i % 10;
i = i / 10;
sum += k;
}
sum += i;
return (isPrime(sum));
}
private boolean isPrime(int num) {
if(num==2)
return true;
// check if n is a multiple of 2
if (num % 2 == 0 || num==1 )
return false;
// if not, then just check the odds
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0)
return false;
}
return true;
}
}
/**
*
* @author cypronmaya
*/
import java.util.Scanner;
class Solution {
boolean[] check;
public static void main(String[] args) {
Solution sr = new Solution();
sr.sieve(3358);
Scanner scanner = new Scanner(System.in);
int no_cases = scanner.nextInt();
for (int i = 0; i < no_cases; i++) {
System.out.println(sr.solve(scanner.nextLong(), scanner.nextLong()));
}
}
private int solve(long l, long m) {
int count = 0;
for (long i = l; i <= m; i++) {
if (logic(i)) {
count++;
}
}
return count;
}
private boolean logic(long i) {
return (isSUM_SUMsq(i));
}
private boolean isSUM_SUMsq(long i)
{
int sum = 0;
int sumsq=0;
while (i > 9) {
long k = i % 10;
i = i / 10;
sum += k;
sumsq += k * k;
}
sum += i;
sumsq +=i*i;
if(check[sum])
{
return check[sumsq];
}
return false;
}
private void sieve(int upto) {
int N = upto;
boolean[] isPrime = new boolean[N + 1];
for (int i = 2; i <= N; i++) {
isPrime[i] = true;
}
for (int i = 2; i * i <= N; i++) {
if (isPrime[i]) {
for (int j = i; i * j <= N; j++) {
isPrime[i * j] = false;
}
}
}
this.check = isPrime;
}
}
@The111
Copy link

The111 commented Feb 15, 2012

@nagendracse
"So the main problem is that given A and B we are iterating over every elements . we need to find a way so that we can skip few elements in between"
True. Or make each iteration much faster, which I was able to do my removing 90% of the modulo and division operations from my loops. In the end it sped my code up by a factor of 10 on my machine. But did not even change by any significant amount the execution of testcases on the InterviewStreet servers.

@adevtus
Copy link

adevtus commented Feb 15, 2012

@The111
I got those testcases by throwing an exception with the input that was given, the site will print out a short message with the exception that was thrown. I'm not really sure if the numbers are correct. So far I'm only able to pass the first testcase, how many testcases does your solution pass? Have you used any particular algorithms or just programmer's intuition?
As far as passing all testcases, I think it's impossible, you need to be a top-level coder but it's good exercise and I did learn a lot.

@saran87
Copy link

saran87 commented Feb 16, 2012

I sorted the digits and stored in a table.so next time a number with same digits come . It simply skips.
For example:

no : 12345 is equal to 53421 and 42315.

More over I discarded the zero if it occurs in the number. so 1023 will be considered as 123 .

But this also didn't helped me. It ran same time as brute force.

@balanfest01
Copy link

Here is how I know this challenge is impossible. The following code does nothing more than read the first line from the input file (the number of test cases) and then print zero for every single one. Of course it is going to be incorrect. But guess what else. It takes 4.4 seconds on InterviewStreet test server! That leaves 0.6 seconds to compute sums of digits and check if they are prime. Not very realistic at all. Try this code yourself!

import java.io.*;

public class Solution
{
    public static void main(String[] args)
    {
        int numOfTests = 0;
        int[] lucky;
        BufferedReader myReader = null;
        try
        {
            myReader = new BufferedReader(new InputStreamReader(System.in));
            numOfTests = Integer.parseInt(myReader.readLine());
        }
        catch (Exception e)
        {
            System.err.println("Error:" + e.getMessage());
        }
        lucky = new int[numOfTests];
        int i = 0;
        for ( ; i < numOfTests - 1; i++)
        {
            System.out.println(lucky[i]);
        }
        System.out.print(lucky[i]);
    }
}

@The111
Copy link

The111 commented Feb 18, 2012

Some new ideas to toss around:
There are two main loops to this thing:
outer loop: iterate through test cases
inner loop: iterate through each number in the range of the current test case
As a test, if you reduce the inner loop to only perform one trivial calculation (i.e. not even check for primality) you will exceed the time limit. Further testing has also shown that you are always cut off after more than 5 seconds in a loop. So you don't know exactly HOW much you are exceeding the time limit by. But by playing with the size of the inner loop, it is possible to iterate up to 20,000 times and stay under the time limit (so obviously the ranges involved in each case are much larger than that).
The conclusion is one that nagendracse made already. It is simply impossible to check every single number in each test range and stay within the time limit. So some sort of pattern must be detected in the digit sums, and then by simply looking at the lower and upper limits of the range of the current test case, you can somehow determine how many lucky numbers are within that range. Maybe you have to check some of the numbers within that range, but at the very most you can perform ~20,000 checks per test case (probably far less if your check loop has more than one trivial calculation).
If it was possible to cut and paste a ridiculous amount of code, and if it didn't require more than 256MB, I'd suggest tabulating the entire table of lucky numbers from 1 to 10^18. Obviously not possible, but I am thinking about generating a text listing of that data, just so I can try to search it for patterns. I am fairly confident that is the key to this puzzle. Maybe some sort of binary search that allows you to zero in on certain subranges in the "top range" 1 to 10^18, using a reasonable amount of operations.

@saran87
Copy link

saran87 commented Feb 20, 2012 via email

@The111
Copy link

The111 commented Feb 20, 2012

I found those values through an algorithm, starting small with ranges like 1-100, 1-1000, etc, that were easy to verify my algorithm was working right. They may not be right, I still have a lot of verification to do.

@thahir
Copy link

thahir commented Mar 11, 2012

hi i want a csharp solution to this problem pls help i am not able to take input as needed to be taken

@adevtus
Copy link

adevtus commented Mar 12, 2012

@thahir
I've uploaded my C# solution for this problem: https://gist.github.com/2020902
Let me know if it helps

@saran87
Copy link

saran87 commented Mar 15, 2012 via email

@saran87
Copy link

saran87 commented Jun 8, 2012 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment