PalindromeCheck efficiency for Int in Java - java

I have constructed two ways to check palindrome of a number. Which one is more efficient? By efficiency, I mean in terms of execution time and memory allocations.
First, I convert an Integer to string and check if it is a palindrome. The example of code is as follow.
public class Palindrome{
/*
Function palindromeCheck
Return type boolean
Parameters characterArray
Checks character array for palindrome
*/
public static boolean palindromeCheck(char[] palinCheck){
boolean palindrome = true;
int firstLen = 0;
int secondLen = palinCheck.length - 1;
while(palindrome == true && firstLen < secondLen ){
if(palinCheck[firstLen] != palinCheck[secondLen]){
palindrome = false;
}
else{
firstLen++;
secondLen--;
}
} //end of while
return palindrome;
}
/*Main Function
Calls palinDromeCheck function
Prints results
*/
public static void main(String[] args){
int palinCheck = 1221;
String dipendra = Integer.toString(palinCheck);
char[] dipendraChar = dipendra.toCharArray();
System.out.println(palindromeCheck(dipendraChar));
}
}
The second method is without converting it to string.
public class PalindromeNumber{
/*
Function: PalindromeCheck
parameters integer
ReturnType: boolean
Takes integer, checks if it is palindrome and returns accordingly
*/
public static boolean palindromeCheck(int number){
int firstNumber = number;
int secondNumber = 0;
while(number >= 1){
secondNumber = secondNumber* 10 + (number%10);
number = number/10;
}
return (firstNumber==secondNumber) ? true:false;
}
public static void main(String[] args){
System.out.println(palindromeCheck(111));
}
}

I bet the second algorithm would be faster, and obviously more space efficient. If you assume n be the number of digits of the input number, in the first algorithm:
Integer.toString requires n steps to convert it to String.
palindromeCheck requires n / 2 comparisons to check whether it's a palindrome.
But, the second algorithm would require n steps to compute the reverse number (involving only integer operations) and only 1 comparison to check.

Let's try.
On the following example (with one specific number, on my specific machine...) :
580 ms - Your first solution
323 ms - Your second solution
1045 ms - BrentR's solution
Note I modified the code a bit (but not the logic). You should also take care of spaces and indentation.
public class Palindrome {
public static boolean isPalindrome1(int n) {
char a[] = Integer.toString(n).toCharArray();
int i = 0;
int j = a.length - 1;
while (i < j) {
if (a[i++] != a[j--]) return false;
}
return true;
}
public static boolean isPalindrome2(int n) {
int p = n, q = 0;
while (n > 0) {
q = 10 * q + n % 10;
n /= 10;
}
return p == q;
}
public static boolean isPalindrome3(int n) {
String s = Integer.toString(n);
return s.equalsIgnoreCase(new StringBuilder(s).reverse().toString());
}
public static void main(String[] args) {
final int m = 10000000;
long t1, t2;
boolean q;
t1 = System.currentTimeMillis();
for (int n = 0; n < m; n++) {
q = isPalindrome1(123454321);
}
t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
t1 = System.currentTimeMillis();
for (int n = 0; n < m; n++) {
q = isPalindrome2(123454321);
}
t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
t1 = System.currentTimeMillis();
for (int n = 0; n < m; n++) {
q = isPalindrome3(123454321);
}
t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
}

Why are you re-inventing the wheel?
java.lang.StringBuilder already provides a string reverse method
String string = Integer.toString(10101);
boolean palindrome = string.equalsIgnoreCase(new StringBuilder(string).reverse().toString());

Related

How to generate combination of numbers in more optimized way in Java?

I had a problem statement which requires passing 3 different numbers to a method and checking which 3 numbers satisfies a certain constraint.
Here is my code, but I wanted to know instead of creating nested loops, is there any more optimized way of checking which set of triplet satisfies a certain constraint. ?
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution
{
static List l = new ArrayList();
static int geometricTrick(String s)
{
int count = 0;
for (int i = 0; i < s.length(); i++)
{
for (int j = 0; j < s.length(); j++)
{
for (int k = 0; k < s.length(); k++)
{
if (is1stConstraintTrue(s, i, j, k) && is2ndConstraintTrue(i, j, k))
{
l.add(new Triplet(i, j, k));
}
}
}
}
count = l.size();
return count;
}
static boolean is2ndConstraintTrue(int i, int j, int k)
{
boolean retVal = false;
double LHS = Math.pow((j + 1), 2);
double RHS = (i + 1) * (k + 1);
if (LHS == RHS)
retVal = true;
else
retVal = false;
return retVal;
}
static boolean is1stConstraintTrue(String s, int i, int j, int k)
{
boolean retVal = false;
char[] localChar = s.toCharArray();
if (localChar[i] == 'a' && localChar[j] == 'b' && localChar[k] == 'c')
{
retVal = true;
}
return retVal;
}
static class Triplet
{
public int i, j, k;
public Triplet(int i, int j, int k)
{
this.i= i;
this.j= j;
this.k= k;
}
}
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String s = in.next();
int result = geometricTrick(s);
System.out.println(result);
}
}
Here are some hints:
Computing the square by multiplication will be faster than using pow
String::toCharray() is expensive. It copies all characters into a new array. Each time you call it. Don't call it multiple times.
If the result is the number of triples, you don't need to build a list. You don't even need to create Triple instances. Just count them.
Nested loops are not inefficient, if you need to iterate all combinations.
To provide you a simple and "stupid" solution to not use those inner loops.
Let's use a Factory like an Iterator. This would "hide" the loop by using condition statement.
public class TripletFactory{
final int maxI, maxJ, maxK;
int i, j ,k;
public TripletFactory(int i, int j, int k){
this.maxI = i;
this.maxJ = j;
this.maxK = k;
}
public Triplet next(){
if(++k > maxK){
k = 0;
if(++j > maxJ){
j = 0;
if(++i > maxI){
return null;
}
}
}
return new Triplet(i,j,k);
}
}
That way, you just have to get a new Triple until a null instance in ONE loop
TripletFactory fact = new TripletFactory(2, 3 ,5);
Triplet t = null;
while((t = fact.next()) != null){
System.out.println(t);
}
//no more Triplet
And use it like you want.
Then, you will have to update your constraint method to take a Triplet and use the getters to check the instance.
That could be a method of Triplet to let it validate itself by the way.
Note :
I used the same notation as the Iterator because we could implement Iterator and Iterable to use a notation like :
for(Triplet t : factory){
...
}
The naive approach you presented has cubic time complexity (three nested for-loops). If you have many occurrences of 'a', 'b' and 'c' within your input, it may be worth wile to first determine the indices of all 'a''s, 'b''s and 'c''s and then check your second condition only over this set.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Integer> getAllOccurrences(String input, char of) {
List<Integer> occurrences = new ArrayList<Integer>();
char[] chars = input.toCharArray();
for (int idx = 0; idx < chars.length; ++idx) {
if (of == chars[idx]) {
occurrences.add(idx);
}
}
return (occurrences);
}
static List<Triplet> geometricTrick(String input){
List<Integer> allAs = getAllOccurrences(input, 'a');
List<Integer> allBs = getAllOccurrences(input, 'b');
List<Integer> allCs = getAllOccurrences(input, 'c');
List<Triplet> solutions = new ArrayList<Triplet>();
// reorder the loops, so that the c-loop is the innermost loop (see
// below why this is useful and how it is exploited).
for (int a : allAs) {
for (int c : allCs) {
// calculate lhs as soon as possible, no need to recalculate the
// same value multiple times
final int lhs = ((a + 1) * (c + 1));
for (int b : allBs) {
final int rhs = ((b + 1) * (b + 1));
if (lhs > rhs) {
continue;
}
/* else */ if (lhs == rhs) {
solutions.add(new Triplet(a, b, c));
}
// by construction, the b-values are in ascending or der.
// Thus if the rhs-value is larger or equal to the
// lhs-value, we can skip all other rhs-values. for this
// lhs-value.
// if (lhs <= rhs) {
break;
// }
}
}
}
return (solutions);
}
static class Triplet {
public final int i;
public final int j;
public final int k;
public Triplet(int i, int j, int k) {
this.i = i;
this.j = j;
this.k = k;
}
}
}
Searching all occurrences of one char within a given String takes O(n) (method getAllOccurrences(...)), calling it three times does not change the complexity (3 * n \in O(n)). Iterating through all possible combinations of a, b and c takes #a * #b * #c time, where #a, #b and #c stay for the count of a's, b's and c's in your input. This gives a total time complexity of O(n + #a * #b * #c).
Note that the worst case time complexity, i.e. if 1/3 of your string consists of a's, 1/3 consists of b's and 1/3 consists of c's, is still cubic.

Wordlist generator that support BigIntegers for Huge Numbers

I need a help to complete a program that will generate a wordlist from chosen characters and length (it need to support a big length).
At first you need to fix this both by adding the length (wordlength) wanted and making a string of the specified characters(alphabet).
So the full number of words is:
long MAX_WORDS = (long) Math.pow(alphabet.length(), wordlength);
Actually, I made it and it work (for the example of short word of 2 or 66 characters).
import java.math.BigInteger;
public class wordlistgenenreg {
public static void main(String[] args) {
generate();
}
private static void generate(){
int wordlength =2;
String alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~";
final long MAX_WORDS = (long) Math.pow(alphabet.length(), wordlength);
final int RADIX = alphabet.length();
for (long i = 0; i < MAX_WORDS; i++) {
int[] indices = convertToRadix(RADIX, i, wordlength);
char[] word = new char[wordlength];
for (int k = 0; k < wordlength; k++) {word[k] = alphabet.charAt(indices[k]);}
String fullword=new String(word);
System.out.println(fullword);
}
System.out.println("completed!");
}
private static int[] convertToRadix(int radix, long number, int wordlength) {
int[] indices = new int[wordlength];
for (int i = wordlength - 1; i >= 0; i--) {
if (number > 0) {
int rest = (int) (number % radix);
number /= radix;
indices[i] = rest;
} else {
indices[i] = 0;
}
}
return indices;
}
}
but there are a problem when i want to generate a really big string of 64 characters from 66. Because:
MAX_WORDS = 66^64 = 282365657377235405270307754780751252031361330095689004197961218014051357270480550051149871489969454245263206971867136
So I tried to change it to make it work with the BigInteger. But us a result, I always obtain the String:
"0000000000000000000000000000000000000000000000000000000000000000"
So there are a problem that i didn't figure it out. This my work on changing it:
import java.math.BigInteger;
public class wordlistgen {
public static void main(String[] args) {
generate();
}
private static void generate() {
int wordlength = 64;
String alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~";
BigInteger max_words=new BigInteger("282365657377235405270307754780751252031361330095689004197961218014051357270480550051149871489969454245263206971867136");
final int RADIX = alphabet.length();
BigInteger plus=BigInteger.valueOf(1);
for (BigInteger i = new BigInteger("0"); i.compareTo(max_words) <0; i.add(plus)) {
int[] indices = convertToRadix(RADIX, i, wordlength);
char[] word = new char[wordlength];
for (int k = 0; k < wordlength; k++) {word[k] = alphabet.charAt(indices[k]);}
String fullword=new String(word);
System.out.println(fullword);
}
}
private static int[] convertToRadix(int radix, BigInteger i2, int wordlength) {
BigInteger zero=BigInteger.valueOf(0);
BigInteger big_radix=BigInteger.valueOf(radix);
int[] indices = new int[wordlength];
for (int i = wordlength - 1; i >= 0; i--) {
if (i2.compareTo(zero)==0) {
BigInteger rest =i2.remainder(big_radix);
BigInteger ab=i2.divide(big_radix);
i2=ab;
indices[i] = rest.intValue();
} else {
indices[i] = 0;
}
}
return indices;
}
}
This is the if from your original version:
if (number > 0) {
int rest = (int) (number % radix);
number /= radix;
indices[i] = rest;
} else {
indices[i] = 0;
}
And the same if in the BigInteger version:
if (i2.compareTo(zero)==0) {
BigInteger rest =i2.remainder(big_radix);
BigInteger ab=i2.divide(big_radix);
i2=ab;
indices[i] = rest.intValue();
} else {
indices[i] = 0;
}
As you can see, in your new if, you are asking if number == 0 instead of number > 0. So you always end up in the else.
As a side note: you are running a loop from 0 to your max_words. If each iteration takes merely a nanosecond to complete, it will still take 368788667672120349090672500612638816231217766896306723928560063188563281831044121479026746095987887263264265 years. Enough time for the universe to disintegrate into full entropy. I'd suggest re-thinking your algorithm.

Cutting of the first 9 digits

Alright I am trying to solve a challenge one of my friends gave me to do, well I've manged to cut the last 9 digits out of a BigInteger well I had a way to cut-off the first 9 but it was so slow, it was taking too long.
The reason I need the first 9 and the last 9 is because I am looking for a BigInteger where the first and last are pandigital.
If you do not understand what I mean say we have n = new BigInteger("123456789987654321") well I need to get the "123456789" and the "987654321" seperately, and I do NOT want to convert the BigInteger to a string because that's a VERY slow process.
I am going for speed here, I am just stumped on this solution. I've heard something about using the Golden Ratio? Here is my code if you're interested.
import java.math.BigInteger;
public class Main {
public static void main(String...strings)
{
long timeStart = System.currentTimeMillis();
fib(350_000);
long timeEnd = System.currentTimeMillis();
System.out.println("Finished processing, time: " + (timeEnd - timeStart) + " milliseconds.");
}
public static BigInteger fib(int n)
{
BigInteger prev1 = BigInteger.valueOf(0), prev2 = BigInteger.valueOf(1);
for (int i = 0; i < n; i++)
{
// TODO: Check if the head is pandigital as well.
BigInteger tailing9Digits = tailing9Digits(prev1);
boolean tailPandigital = isPanDigital(tailing9Digits);
if (tailPandigital)
{
System.out.println("Solved at index: " + i);
break;
}
BigInteger savePrev1 = prev1;
prev1 = prev2;
prev2 = savePrev1.add(prev2);
}
return prev1;
}
public static BigInteger leading9Digits(BigInteger x)
{
// STUCK HERE.
return null;
}
public static BigInteger tailing9Digits(BigInteger x)
{
return x.remainder(BigInteger.TEN.pow(9));
}
static BigInteger[] pows = new BigInteger[16];
static
{
for (int i = 0; i < 16; i++)
{
pows[i] = BigInteger.TEN.pow(i);
}
}
static boolean isPanDigital(BigInteger n)
{
if (!n.remainder(BigInteger.valueOf(9)).equals(BigInteger.ZERO))
{
return false;
}
boolean[] foundDigits = new boolean[9];
boolean isPanDigital = true;
for (int i = 1; i <= 9; i++)
{
BigInteger digit = n.remainder(pows[i]).divide(pows[i - 1]);
for (int j = 0; j < foundDigits.length; j++) {
if (digit.equals(BigInteger.valueOf(j + 1)) && !foundDigits[j])
{
foundDigits[j] = true;
}
}
}
for (int i = 0; i < 9; i++)
{
isPanDigital = isPanDigital && foundDigits[i];
}
return isPanDigital;
}
}
BigInteger isn't something I'd recommend using if you care at all about speed. Most of its methods are poorly-implemented, and this typically results in very slow code.
There's a divide-and-conquer trick for division and radix conversion that you might find helpful.
First, BigInteger's multiply() is quadratic. You'll need to work around that, otherwise these divide-and-conquer tricks won't lead to any speedup. Multiplication via the fast Fourier transform is reasonably fast and good.
If you want to convert a BigInteger to base 10, break it in half (bitwise) and write it as a * 256^k + b. One thing you can do is convert a and b to base-10 recursively, then convert 256^k to decimal by repeated squaring, and then, in base 10, multiply a by 256^k and add b to the result. Also, since you're only interested in the first few digits, you might not even need to convert b if the first few digits of a * 256^k can't possibly be influenced by adding something as small as b.
A similar trick works for division.
You can do bit-shifting and extraction using the toByteArray() method.
Well I believe this is what you need:
import java.math.BigInteger;
public class PandigitalCheck {
public static void main(String[] args) {
BigInteger num = new BigInteger("12345678907438297438924239987654321");
long timeStart = System.currentTimeMillis();
System.out.println("Is Pandigital: " + isPandigital(num));
long timeEnd = System.currentTimeMillis();
System.out.println("Time Taken: " + (timeEnd - timeStart) + " ms");
}
private static boolean isPandigital(BigInteger num) {
if (getTrailing9Digits(num).compareTo(getLeading9Digits(num)) == 0) {
return true;
}
return false;
}
private static BigInteger getLeading9Digits(BigInteger num) {
int length = getBigIntLength(num);
BigInteger leading9 = BigInteger.ZERO;
for (int i = 0; i < 9; i++) {
BigInteger remainder = num.divide(BigInteger.TEN.pow(length - 1 - i));
leading9 = leading9.add(remainder.multiply(BigInteger.TEN.pow(i)));
num = num.remainder(BigInteger.TEN.pow(length - 1 - i));
}
return leading9;
}
private static int getBigIntLength(BigInteger num) {
for (int i = 1; ; i++) {
if (num.divide(BigInteger.TEN.pow(i)) == BigInteger.ZERO) {
return i;
}
}
}
private static BigInteger getTrailing9Digits(BigInteger num) {
return num.remainder(BigInteger.TEN.pow(9));
}
}
The output is:
Is Pandigital: true
Time Taken: 0 ms
Does it fit the bill?
I’m newbie for java, I’m converting BigInteger to String only but it's little bit fast as your code
import java.math.BigInteger;
public class Main {
public static void main(String args[])
{
long timeStart = System.currentTimeMillis();
String biStr = new BigInteger("123456789987654321").toString();
int length=(biStr.length())/2;
String[] ints = new String[length];
String[] ints2 = new String[length];
for(int i=0; i<length; i++) {
int j=i+length;
ints[i] = String.valueOf(biStr.charAt(i));
ints2[i] = String.valueOf(biStr.charAt(j));
System.out.println(ints[i] +" | "+ints2[i]);
}
long timeEnd = System.currentTimeMillis();
System.out.println("Finished processing, time: " + (timeEnd - timeStart) + " milliseconds.");
}
}
Maybe this is not too fast but at least it's simple
BigInteger n = new BigInteger("123456789987654321");
BigInteger n2 = n.divide(BigInteger.TEN.pow(new BigDecimal(n).precision() - 9));
BigInteger n1 = n.remainder(new BigInteger("1000000000"));
System.out.println(n1);
System.out.println(n2);
output
987654321
123456789

Find factorial of large numbers in Java

I tried to find the factorial of a large number e.g. 8785856 in a typical way using for-loop and double data type.
But it is displaying infinity as the result, may be because it is exceeding its limit.
So please guide me the way to find the factorial of a very large number.
My code:
class abc
{
public static void main (String[]args)
{
double fact=1;
for(int i=1;i<=8785856;i++)
{
fact=fact*i;
}
System.out.println(fact);
}
}
Output:-
Infinity
I am new to Java but have learned some concepts of IO-handling and all.
public static void main(String[] args) {
BigInteger fact = BigInteger.valueOf(1);
for (int i = 1; i <= 8785856; i++)
fact = fact.multiply(BigInteger.valueOf(i));
System.out.println(fact);
}
You might want to reconsider calculating this huge value. Wolfram Alpha's Approximation suggests it will most certainly not fit in your main memory to be displayed.
This code should work fine :-
public class BigMath {
public static String factorial(int n) {
return factorial(n, 300);
}
private static String factorial(int n, int maxSize) {
int res[] = new int[maxSize];
res[0] = 1; // Initialize result
int res_size = 1;
// Apply simple factorial formula n! = 1 * 2 * 3 * 4... * n
for (int x = 2; x <= n; x++) {
res_size = multiply(x, res, res_size);
}
StringBuffer buff = new StringBuffer();
for (int i = res_size - 1; i >= 0; i--) {
buff.append(res[i]);
}
return buff.toString();
}
/**
* This function multiplies x with the number represented by res[]. res_size
* is size of res[] or number of digits in the number represented by res[].
* This function uses simple school mathematics for multiplication.
*
* This function may value of res_size and returns the new value of res_size.
*/
private static int multiply(int x, int res[], int res_size) {
int carry = 0; // Initialize carry.
// One by one multiply n with individual digits of res[].
for (int i = 0; i < res_size; i++) {
int prod = res[i] * x + carry;
res[i] = prod % 10; // Store last digit of 'prod' in res[]
carry = prod / 10; // Put rest in carry
}
// Put carry in res and increase result size.
while (carry != 0) {
res[res_size] = carry % 10;
carry = carry / 10;
res_size++;
}
return res_size;
}
/** Driver method. */
public static void main(String[] args) {
int n = 100;
System.out.printf("Factorial %d = %s%n", n, factorial(n));
}
}
Hint: Use the BigInteger class, and be prepared to give the JVM a lot of memory. The value of 8785856! is a really big number.
Use the class BigInteger. ( I am not sure if that will even work for such huge integers )
Infinity is a special reserved value in the Double class used when you have exceed the maximum number the a double can hold.
If you want your code to work, use the BigDecimal class, but given the input number, don't expect your program to finish execution any time soon.
The above solutions for your problem (8785856!) using BigInteger would take literally hours of CPU time if not days. Do you need the exact result or would an approximation suffice?
There is a mathematical approach called "Sterling's Approximation
" which can be computed simply and fast, and the following is Gosper's improvement:
import java.util.*;
import java.math.*;
class main
{
public static void main(String args[])
{
Scanner sc= new Scanner(System.in);
int i;
int n=sc.nextInt();
BigInteger fact = BigInteger.valueOf(1);
for ( i = 1; i <= n; i++)
{
fact = fact.multiply(BigInteger.valueOf(i));
}
System.out.println(fact);
}
}
Try this:
import java.math.BigInteger;
public class LargeFactorial
{
public static void main(String[] args)
{
int n = 50;
}
public static BigInteger factorial(int n)
{
BigInteger result = BigInteger.ONE;
for (int i = 1; i <= n; i++)
result = result.multiply(new BigInteger(i + ""));
return result;
}
}
Scanner r = new Scanner(System.in);
System.out.print("Input Number : ");
int num = r.nextInt();
int ans = 1;
if (num <= 0) {
ans = 0;
}
while (num > 0) {
System.out.println(num + " x ");
ans *= num--;
}
System.out.println("\b\b=" + ans);
public static void main (String[] args) throws java.lang.Exception
{
BigInteger fact= BigInteger.ONE;
int factorialNo = 8785856 ;
for (int i = 2; i <= factorialNo; i++) {
fact = fact.multiply(new BigInteger(String.valueOf(i)));
}
System.out.println("Factorial of the given number is = " + fact);
}
import java.util.Scanner;
public class factorial {
public static void main(String[] args) {
System.out.println("Enter the number : ");
Scanner s=new Scanner(System.in);
int n=s.nextInt();
factorial f=new factorial();
int result=f.fact(n);
System.out.println("factorial of "+n+" is "+result);
}
int fact(int a)
{
if(a==1)
return 1;
else
return a*fact(a-1);
}
}

Fastest algorithm to check if a number is pandigital?

Pandigital number is a number that contains the digits 1..number length.
For example 123, 4312 and 967412385.
I have solved many Project Euler problems, but the Pandigital problems always exceed the one minute rule.
This is my pandigital function:
private boolean isPandigital(int n){
Set<Character> set= new TreeSet<Character>();
String string = n+"";
for (char c:string.toCharArray()){
if (c=='0') return false;
set.add(c);
}
return set.size()==string.length();
}
Create your own function and test it with this method
int pans=0;
for (int i=123456789;i<=123987654;i++){
if (isPandigital(i)){
pans++;
}
}
Using this loop, you should get 720 pandigital numbers. My average time was 500 millisecond.
I'm using Java, but the question is open to any language.
UPDATE
#andras answer has the best time so far, but #Sani Huttunen answer inspired me to add a new algorithm, which gets almost the same time as #andras.
C#, 17ms, if you really want a check.
class Program
{
static bool IsPandigital(int n)
{
int digits = 0; int count = 0; int tmp;
for (; n > 0; n /= 10, ++count)
{
if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1)))
return false;
}
return digits == (1 << count) - 1;
}
static void Main()
{
int pans = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 123456789; i <= 123987654; i++)
{
if (IsPandigital(i))
{
pans++;
}
}
sw.Stop();
Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds);
Console.ReadKey();
}
}
For a check that is consistent with the Wikipedia definition in base 10:
const int min = 1023456789;
const int expected = 1023;
static bool IsPandigital(int n)
{
if (n >= min)
{
int digits = 0;
for (; n > 0; n /= 10)
{
digits |= 1 << (n - ((n / 10) * 10));
}
return digits == expected;
}
return false;
}
To enumerate numbers in the range you have given, generating permutations would suffice.
The following is not an answer to your question in the strict sense, since it does not implement a check. It uses a generic permutation implementation not optimized for this special case - it still generates the required 720 permutations in 13ms (line breaks might be messed up):
static partial class Permutation
{
/// <summary>
/// Generates permutations.
/// </summary>
/// <typeparam name="T">Type of items to permute.</typeparam>
/// <param name="items">Array of items. Will not be modified.</param>
/// <param name="comparer">Optional comparer to use.
/// If a <paramref name="comparer"/> is supplied,
/// permutations will be ordered according to the
/// <paramref name="comparer"/>
/// </param>
/// <returns>Permutations of input items.</returns>
public static IEnumerable<IEnumerable<T>> Permute<T>(T[] items, IComparer<T> comparer)
{
int length = items.Length;
IntPair[] transform = new IntPair[length];
if (comparer == null)
{
//No comparer. Start with an identity transform.
for (int i = 0; i < length; i++)
{
transform[i] = new IntPair(i, i);
};
}
else
{
//Figure out where we are in the sequence of all permutations
int[] initialorder = new int[length];
for (int i = 0; i < length; i++)
{
initialorder[i] = i;
}
Array.Sort(initialorder, delegate(int x, int y)
{
return comparer.Compare(items[x], items[y]);
});
for (int i = 0; i < length; i++)
{
transform[i] = new IntPair(initialorder[i], i);
}
//Handle duplicates
for (int i = 1; i < length; i++)
{
if (comparer.Compare(
items[transform[i - 1].Second],
items[transform[i].Second]) == 0)
{
transform[i].First = transform[i - 1].First;
}
}
}
yield return ApplyTransform(items, transform);
while (true)
{
//Ref: E. W. Dijkstra, A Discipline of Programming, Prentice-Hall, 1997
//Find the largest partition from the back that is in decreasing (non-icreasing) order
int decreasingpart = length - 2;
for (;decreasingpart >= 0 &&
transform[decreasingpart].First >= transform[decreasingpart + 1].First;
--decreasingpart) ;
//The whole sequence is in decreasing order, finished
if (decreasingpart < 0) yield break;
//Find the smallest element in the decreasing partition that is
//greater than (or equal to) the item in front of the decreasing partition
int greater = length - 1;
for (;greater > decreasingpart &&
transform[decreasingpart].First >= transform[greater].First;
greater--) ;
//Swap the two
Swap(ref transform[decreasingpart], ref transform[greater]);
//Reverse the decreasing partition
Array.Reverse(transform, decreasingpart + 1, length - decreasingpart - 1);
yield return ApplyTransform(items, transform);
}
}
#region Overloads
public static IEnumerable<IEnumerable<T>> Permute<T>(T[] items)
{
return Permute(items, null);
}
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> items, IComparer<T> comparer)
{
List<T> list = new List<T>(items);
return Permute(list.ToArray(), comparer);
}
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> items)
{
return Permute(items, null);
}
#endregion Overloads
#region Utility
public static IEnumerable<T> ApplyTransform<T>(
T[] items,
IntPair[] transform)
{
for (int i = 0; i < transform.Length; i++)
{
yield return items[transform[i].Second];
}
}
public static void Swap<T>(ref T x, ref T y)
{
T tmp = x;
x = y;
y = tmp;
}
public struct IntPair
{
public IntPair(int first, int second)
{
this.First = first;
this.Second = second;
}
public int First;
public int Second;
}
#endregion
}
class Program
{
static void Main()
{
int pans = 0;
int[] digits = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Stopwatch sw = new Stopwatch();
sw.Start();
foreach (var p in Permutation.Permute(digits))
{
pans++;
if (pans == 720) break;
}
sw.Stop();
Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds);
Console.ReadKey();
}
}
This is my solution:
static char[][] pandigits = new char[][]{
"1".toCharArray(),
"12".toCharArray(),
"123".toCharArray(),
"1234".toCharArray(),
"12345".toCharArray(),
"123456".toCharArray(),
"1234567".toCharArray(),
"12345678".toCharArray(),
"123456789".toCharArray(),
};
private static boolean isPandigital(int i)
{
char[] c = String.valueOf(i).toCharArray();
Arrays.sort(c);
return Arrays.equals(c, pandigits[c.length-1]);
}
Runs the loop in 0.3 seconds on my (rather slow) system.
Two things you can improve:
You don't need to use a set: you can use a boolean array with 10 elements
Instead of converting to a string, use division and the modulo operation (%) to extract the digits.
Using a bit vector to keep track of which digits have been found appears to be the fastest raw method. There are two ways to improve it:
Check if the number is divisible by 9. This is a necessary condition for being pandigital, so we can exclude 88% of numbers up front.
Use multiplication and shifts instead of divisions, in case your compiler doesn't do that for you.
This gives the following, which runs the test benchmark in about 3ms on my machine. It correctly identifies the 362880 9-digit pan-digital numbers between 100000000 and 999999999.
bool IsPandigital(int n)
{
if (n != 9 * (int)((0x1c71c71dL * n) >> 32))
return false;
int flags = 0;
while (n > 0) {
int q = (int)((0x1999999aL * n) >> 32);
flags |= 1 << (n - q * 10);
n = q;
}
return flags == 0x3fe;
}
My solution involves Sums and Products.
This is in C# and runs in about 180ms on my laptop:
static int[] sums = new int[] {1, 3, 6, 10, 15, 21, 28, 36, 45};
static int[] products = new int[] {1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
static void Main(string[] args)
{
var pans = 0;
for (var i = 123456789; i <= 123987654; i++)
{
var num = i.ToString();
if (Sum(num) == sums[num.Length - 1] && Product(num) == products[num.Length - 1])
pans++;
}
Console.WriteLine(pans);
}
protected static int Sum(string num)
{
int sum = 0;
foreach (char c in num)
sum += (int) (c - '0');
return sum;
}
protected static int Product(string num)
{
int prod = 1;
foreach (char c in num)
prod *= (int)(c - '0');
return prod;
}
Why find when you can make them?
from itertools import *
def generate_pandigital(length):
return (''.join for each in list(permutations('123456789',length)))
def test():
for i in range(10):
print i
generate_pandigital(i)
if __name__=='__main__':
test()
J does this nicely:
isPandigital =: 3 : 0
*./ (' ' -.~ ": 1 + i. # s) e. s =. ": y
)
isPandigital"0 (123456789 + i. 1 + 123987654 - 123456789)
But slowly. I will revise. For now, clocking at 4.8 seconds.
EDIT:
If it's just between the two set numbers, 123456789 and 123987654, then this expression:
*./"1 (1+i.9) e."1 (9#10) #: (123456789 + i. 1 + 123987654 - 123456789)
Runs in 0.23 seconds. It's about as fast, brute-force style, as it gets in J.
TheMachineCharmer is right. At least for some the problems, it's better to iterate over all the pandigitals, checking each one to see if it fits the criteria of the problem. However, I think their code is not quite right.
I'm not sure which is better SO etiquette in this case: Posting a new answer or editing theirs. In any case, here is the modified Python code which I believe to be correct, although it doesn't generate 0-to-n pandigitals.
from itertools import *
def generate_pandigital(length):
'Generate all 1-to-length pandigitals'
return (''.join(each) for each in list(permutations('123456789'[:length])))
def test():
for i in range(10):
print 'Generating all %d-digit pandigitals' % i
for (n,p) in enumerate(generate_pandigital(i)):
print n,p
if __name__=='__main__':
test()
You could add:
if (set.add(c)==false) return false;
This would short circuit a lot of your computations, since it'll return false as soon as a duplicate was found, since add() returns false in this case.
bool IsPandigital (unsigned long n) {
if (n <= 987654321) {
hash_map<int, int> m;
unsigned long count = (unsigned long)(log((double)n)/log(10.0))+1;
while (n) {
++m[n%10];
n /= 10;
}
while (m[count]==1 && --count);
return !count;
}
return false;
}
bool IsPandigital2 (unsigned long d) {
// Avoid integer overflow below if this function is passed a very long number
if (d <= 987654321) {
unsigned long sum = 0;
unsigned long prod = 1;
unsigned long n = d;
unsigned long max = (log((double)n)/log(10.0))+1;
unsigned long max_sum = max*(max+1)/2;
unsigned long max_prod = 1;
while (n) {
sum += n % 10;
prod *= (n%10);
max_prod *= max;
--max;
n /= 10;
}
return (sum == max_sum) && (prod == max_prod);
}
I have a solution for generating Pandigital numbers using StringBuffers in Java. On my laptop, my code takes a total of 5ms to run. Of this only 1ms is required for generating the permutations using StringBuffers; the remaining 4ms are required for converting this StringBuffer to an int[].
#medopal: Can you check the time this code takes on your system?
public class GenPandigits
{
/**
* The prefix that must be appended to every number, like 123.
*/
int prefix;
/**
* Length in characters of the prefix.
*/
int plen;
/**
* The digit from which to start the permutations
*/
String beg;
/**
* The length of the required Pandigital numbers.
*/
int len;
/**
* #param prefix If there is no prefix then this must be null
* #param beg If there is no prefix then this must be "1"
* #param len Length of the required numbers (excluding the prefix)
*/
public GenPandigits(String prefix, String beg, int len)
{
if (prefix == null)
{
this.prefix = 0;
this.plen = 0;
}
else
{
this.prefix = Integer.parseInt(prefix);
this.plen = prefix.length();
}
this.beg = beg;
this.len = len;
}
public StringBuffer genPermsBet()
{
StringBuffer b = new StringBuffer(beg);
for(int k=2;k<=len;k++)
{
StringBuffer rs = new StringBuffer();
int l = b.length();
int s = l/(k-1);
String is = String.valueOf(k+plen);
for(int j=0;j<k;j++)
{
rs.append(b);
for(int i=0;i<s;i++)
{
rs.insert((l+s)*j+i*k+j, is);
}
}
b = rs;
}
return b;
}
public int[] getPandigits(String buffer)
{
int[] pd = new int[buffer.length()/len];
int c= prefix;
for(int i=0;i<len;i++)
c =c *10;
for(int i=0;i<pd.length;i++)
pd[i] = Integer.parseInt(buffer.substring(i*len, (i+1)*len))+c;
return pd;
}
public static void main(String[] args)
{
GenPandigits gp = new GenPandigits("123", "4", 6);
//GenPandigits gp = new GenPandigits(null, "1", 6);
long beg = System.currentTimeMillis();
StringBuffer pansstr = gp.genPermsBet();
long end = System.currentTimeMillis();
System.out.println("Time = " + (end - beg));
int pd[] = gp.getPandigits(pansstr.toString());
long end1 = System.currentTimeMillis();
System.out.println("Time = " + (end1 - end));
}
}
This code can also be used for generating all Pandigital numbers(excluding zero). Just change the object creation call to
GenPandigits gp = new GenPandigits(null, "1", 9);
This means that there is no prefix, and the permutations must start from "1" and continue till the length of the numbers is 9.
Following are the time measurements for different lengths.
#andras: Can you try and run your code to generate the nine digit Pandigital numbers? What time does it take?
This c# implementation is about 8% faster than #andras over the range 123456789 to 123987654 but it is really difficult to see on my test box as his runs in 14ms and this one runs in 13ms.
static bool IsPandigital(int n)
{
int count = 0;
int digits = 0;
int digit;
int bit;
do
{
digit = n % 10;
if (digit == 0)
{
return false;
}
bit = 1 << digit;
if (digits == (digits |= bit))
{
return false;
}
count++;
n /= 10;
} while (n > 0);
return (1<<count)-1 == digits>>1;
}
If we average the results of 100 runs we can get a decimal point.
public void Test()
{
int pans = 0;
var sw = new Stopwatch();
sw.Start();
for (int count = 0; count < 100; count++)
{
pans = 0;
for (int i = 123456789; i <= 123987654; i++)
{
if (IsPandigital(i))
{
pans++;
}
}
}
sw.Stop();
Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds / 100m);
}
#andras implementation averages 14.4ms and this implementation averages 13.2ms
EDIT:
It seems that mod (%) is expensive in c#. If we replace the use of the mod operator with a hand coded version then this implementation averages 11ms over 100 runs.
private static bool IsPandigital(int n)
{
int count = 0;
int digits = 0;
int digit;
int bit;
do
{
digit = n - ((n / 10) * 10);
if (digit == 0)
{
return false;
}
bit = 1 << digit;
if (digits == (digits |= bit))
{
return false;
}
count++;
n /= 10;
} while (n > 0);
return (1 << count) - 1 == digits >> 1;
}
EDIT: Integrated n/=10 into the digit calculation for a small speed improvement.
private static bool IsPandigital(int n)
{
int count = 0;
int digits = 0;
int digit;
int bit;
do
{
digit = n - ((n /= 10) * 10);
if (digit == 0)
{
return false;
}
bit = 1 << digit;
if (digits == (digits |= bit))
{
return false;
}
count++;
} while (n > 0);
return (1 << count) - 1 == digits >> 1;
}
#include <cstdio>
#include <ctime>
bool isPandigital(long num)
{
int arr [] = {1,2,3,4,5,6,7,8,9}, G, count = 9;
do
{
G = num%10;
if (arr[G-1])
--count;
arr[G-1] = 0;
} while (num/=10);
return (!count);
}
int main()
{
clock_t start(clock());
int pans=0;
for (int i = 123456789;i <= 123987654; ++i)
{
if (isPandigital(i))
++pans;
}
double end((double)(clock() - start));
printf("\n\tFound %d Pandigital numbers in %lf seconds\n\n", pans, end/CLOCKS_PER_SEC);
return 0;
}
Simple implementation. Brute-forced and computes in about 140 ms
In Java
You can always just generate them, and convert the Strings to Integers, which is faster for larger numbers
public static List<String> permutation(String str) {
List<String> permutations = new LinkedList<String>();
permutation("", str, permutations);
return permutations;
}
private static void permutation(String prefix, String str, List<String> permutations) {
int n = str.length();
if (n == 0) {
permutations.add(prefix);
} else {
for (int i = 0; i < n; i++) {
permutation(prefix + str.charAt(i),
str.substring(0, i) + str.substring(i + 1, n), permutations);
}
}
}
The below code works for testing a numbers pandigitality.
For your test mine ran in around ~50ms
1-9 PanDigital
public static boolean is1To9PanDigit(int i) {
if (i < 1e8) {
return false;
}
BitSet set = new BitSet();
while (i > 0) {
int mod = i % 10;
if (mod == 0 || set.get(mod)) {
return false;
}
set.set(mod);
i /= 10;
}
return true;
}
or more general, 1 to N,
public static boolean is1ToNPanDigit(int i, int n) {
BitSet set = new BitSet();
while (i > 0) {
int mod = i % 10;
if (mod == 0 || mod > n || set.get(mod)) {
return false;
}
set.set(mod);
i /= 10;
}
return set.cardinality() == n;
}
And just for fun, 0 to 9, zero requires extra logic due to a leading zero
public static boolean is0To9PanDigit(long i) {
if (i < 1e6) {
return false;
}
BitSet set = new BitSet();
if (i <= 123456789) { // count for leading zero
set.set(0);
}
while (i > 0) {
int mod = (int) (i % 10);
if (set.get(mod)) {
return false;
}
set.set(mod);
i /= 10;
}
return true;
}
Also for setting iteration bounds:
public static int maxPanDigit(int n) {
StringBuffer sb = new StringBuffer();
for(int i = n; i > 0; i--) {
sb.append(i);
}
return Integer.parseInt(sb.toString());
}
public static int minPanDigit(int n) {
StringBuffer sb = new StringBuffer();
for(int i = 1; i <= n; i++) {
sb.append(i);
}
return Integer.parseInt(sb.toString());
}
You could easily use this code to generate a generic MtoNPanDigital number checker
I decided to use something like this:
def is_pandigital(n, zero_full=True, base=10):
"""Returns True or False if the number n is pandigital.
This function returns True for formal pandigital numbers as well as
n-pandigital
"""
r, l = 0, 0
while n:
l, r, n = l + 1, r + n % base, n / base
t = xrange(zero_full ^ 1, l + (zero_full ^ 1))
return r == sum(t) and l == len(t)
Straight forward way
boolean isPandigital(int num,int length){
for(int i=1;i<=length;i++){
if(!(num+"").contains(i+""))
return false;
}
return true;
}
OR if you are sure that the number is of the right length already
static boolean isPandigital(int num){
for(int i=1;i<=(num+"").length();i++){
if(!(num+"").contains(i+""))
return false;
}
return true;
}
I refactored Andras' answer for Swift:
extension Int {
func isPandigital() -> Bool {
let requiredBitmask = 0b1111111111;
let minimumPandigitalNumber = 1023456789;
if self >= minimumPandigitalNumber {
var resultBitmask = 0b0;
var digits = self;
while digits != 0 {
let lastDigit = digits % 10;
let binaryCodedDigit = 1 << lastDigit;
resultBitmask |= binaryCodedDigit;
// remove last digit
digits /= 10;
}
return resultBitmask == requiredBitmask;
}
return false;
}
}
1023456789.isPandigital(); // true
great answers, my 2 cents
bool IsPandigital(long long number, int n){
int arr[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, amax = 0, amin;
while (number > 0){
int rem = number % 10;
arr[rem]--;
if (arr[rem] < 0)
return false;
number = number / 10;
}
for (int i = 0; i < n; i++){
if (i == 0)
amin = arr[i];
if (arr[i] > amax)
amax = arr[i];
if (arr[i] < amin)
amin = arr[i];
}
if (amax == 0 && amin == 0)
return true;
else
return false;
}

Categories

Resources