Convert from decimal to binary Java error - java

I'm writing a simple Java program to convert from decimal to binary.
public static int toBinary(int n) {
int result = 0;
while (n >= 1) {
int power = 0;
while ((int) Math.pow(2, power) <= n) {
power++;
}
result += (int) Math.pow(10, power - 1);
n = n - (int) Math.pow(2, power - 1);
}
return result;
}
The program works for n up until 1023, but fails after that and I'm not sure where I did wrong. Can someone help?

Your code has a problem of Integer Overflow.
Binary of 1024 is 10,000,000,000 and the max value an int can hold is 2,147,483,647.
Use an int array to store the number:
public static void convertBinary(int num) {
int[] binary = new int[40];
int index = 0;
while (num > 0) {
binary[index++] = num % 2;
num /= 2;
}
for (int i = index - 1; i >= 0; i--){
System.out.print(binary[i]);
}
}
You can also use the in-built method.
System.out.println(Integer.toBinaryString(1024));
You can also use StringBuilder to store the result:
public static void convertBinary(int num){
StringBuilder binary = new StringBuilder();
while (num > 0){
binary.append(num % 2);
num = num / 2;
}
System.out.println(binary.reverse());
}
Do not use String (immutable) in a loop, always use a StringBuilder (mutable).

Related

how can i fix this i want to convert decimal number to binary

public class Binar{
public static void main(String[] args){
int num = 7;
long Binary = cBtD(num);
System.out.printf("%d numri decimal = %d binar" , num, Binary);
}
public static long cBtD(int num){
long BinaryNumber = 0;
int i = 0;
long reminder;
while(num > 0){
reminder = num % 2;
num /= 2;
++i;
}
for (int j = i - 1; j >= 0; j--) {
System.out.print(BinaryNumber[j]);
}
return BinaryNumber;
}}
and i have this error and it says "array required, but long found" and "System.out.print(BinaryNumber[j]);"
Reason behind this error is, you have defined BinaryNumber variable as long and it is not an array. But you are trying to access it like an array. Please check my modified answer below:
public class Binar {
public static void main(String[] args) {
int num = 7;
String Binary = cBtD(num);
System.out.printf("%d numri decimal = %s binar", num, Binary);
}
public static String cBtD(int num) {
String BinaryNumber = "";
long reminder;
if (num == 0) {
return "0";
}
while (num > 0) {
reminder = num % 2;
BinaryNumber = String.valueOf(reminder).concat(BinaryNumber);
num /= 2;
}
return BinaryNumber;
}
}
That error occurred because you defined BinaryNumber's type 'long' and you wanted use it as an array.
I change it a bit, try it:
public class Binar {
public static void main(String[] args) {
int num = 7;
int[] binaryArray = cBtD(num);
String numbers = "";
for (int aBinaryArray : binaryArray)
numbers += aBinaryArray;
System.out.printf("%d numri decimal = %d binar" , num, Integer.parseInt(numbers));
}
private static int[] cBtD(int num){
int i = 0;
int temp[] = new int[7];
int binaryNumber[];
while (num > 0) {
temp[i++] = num % 2;
num /= 2;
}
binaryNumber = new int[i];
int k = 0;
for (int j = i - 1; j >= 0; j--) {
binaryNumber[k++] = temp[j];
}
return binaryNumber;
}
}
Or you can simply use these methods to convert decimal to binary:
Integer.toBinaryString();
Or this:
Integer.toString(n,2);
All numbers are inherently binary. But whether you display them in binary or hex or octal is simply a matter of representation. Which means you want to print them as a string. Even when you do the following:
int v = 123;
System.out.println(v); // v is printed as a decimal string.
So to convert them to a binary string, just prepend the remainders to the string after dividing by two (via the remainder operator).
int n = 11;
String s = "";
s = (n%2) + s; // s = "1"
n/=2; // n == 5
s = (n%2) + s; // s = "11"
n/=2 // n == 2
s = (n%2) + s; // s = "011";
n/=2 // n == 1
s = (n%2) + s; // s = "1011";
n/=2; // n == 0
n == 0 so your done.
return s and print it.

Adding numbers which are stored in string variables

Given two non-negative numbers num1 and num2 represented as strings, return the sum of num1 and num2.
The length of both num1 and num2 is less than 5100.
Both num1 and num2 contain only digits 0-9.
Both num1 and num2 do not contain any leading zeros.
You must not use any built-in BigInteger library or convert the inputs to integer directly.
I tried my solution but it doesn't work. Suggestions?
public class Solution {
public String addStrings(String num1, String num2) {
double multiplier = Math.pow(10, num1.length() - 1);
int sum = 0;
for (int i = 0; i < num1.length(); i++){
sum += ((((int) num1.charAt(i)) - 48) * multiplier);
multiplier /= 10;
}
multiplier = Math.pow(10, num2.length() - 1);
for (int i = 0; i < num2.length(); i++){
sum += ((((int) num2.charAt(i)) - 48) * multiplier);
multiplier /= 10;
}
return "" + sum;
}
}
You must not use any built-in BigInteger library or convert the inputs to integer directly.
Note that you are adding two integers of up to 5100 digits each. That is not that max value, but the max number of digits.
An int (your sum variable) cannot hold values like that. BigInteger can, but you're not allowed to use it.
So, add the numbers like you would on paper: Add last digits, write lower digit of the sum as last digit of result, and carry-over a one if needed. Repeat for second-last digit, third-last digit, etc. until done.
Since the sum will be at least the number of digits of the longest input value, and may be one longer, you should allocate a char[] of length of longest input plus one. When done, construct final string using String(char[] value, int offset, int count), with an offset of 0 or 1 as needed.
The purpose of this question is to add the numbers in the string form. You should not try to convert the strings to integers. The description says the length of the numbers could be up to 5100 digits. So the numbers are simply too big to be stored in integers and doubles. For instance In the following line:
double multiplier = Math.pow(10, num1.length() - 1);
You are trying to store 10^5100 in a double. In IEEE 754 binary floating point standard a double can a store number from ±4.94065645841246544e-324 to ±1.79769313486231570e+308. So your number won't fit. It will instead turn into Infinity. Even if it fits in double it won't be exact and you will encounter some errors in your follow up calculations.
Because the question specifies not to use BigInteger or similar libraries you should try and implement string addition yourself.
This is pretty straightforward just implement the exact algorithm you follow when you add two numbers on paper.
Here is working example of adding two strings without using BigInteger using char array as intermediate container. The point why double can't be used has been explained on #Tempux answer. Here the logic is similar to how adding two numbers on paper works.
public String addStrings(String num1, String num2) {
int carry = 0;
int m = num1.length(), n = num2.length();
int len = m < n ? n : m;
char[] res = new char[len + 1]; // length is maxLen + 1 incase of carry in adding most significant digits
for(int i = 0; i <= len ; i++) {
int a = i < m ? (num1.charAt(m - i - 1) - '0') : 0;
int b = i < n ? (num2.charAt(n - i - 1) - '0') : 0;
res[len - i] = (char)((a + b + carry) % 10 + '0');
carry = (a + b + carry) / 10;
}
return res[0] == '0' ? new String(res, 1, len) : new String(res, 0, len + 1);
}
This snippet is relatively small and precise because here I didn't play with immutable String which is complicated/messy and yield larger code. Also one intuition is - there is no way of getting larger output than max(num1_length, num2_length) + 1 which makes the implementation simple.
You have to addition as you do on paper
you can't use BigInteger and the String Length is 5100, so you can not use int or long for addition.
You have to use simple addition as we do on paper.
class AddString
{
public static void main (String[] args) throws java.lang.Exception
{
String s1 = "98799932345";
String s2 = "99998783456";
//long n1 = Long.parseLong(s1);
//long n2 = Long.parseLong(s2);
System.out.println(addStrings(s1,s2));
//System.out.println(n1+n2);
}
public static String addStrings(String num1, String num2) {
StringBuilder ans = new StringBuilder("");
int n = num1.length();
int m = num2.length();
int carry = 0,sum;
int i, j;
for(i = n-1,j=m-1; i>=0&&j>=0;i--,j--){
int a = Integer.parseInt(""+num1.charAt(i));
int b = Integer.parseInt(""+num2.charAt(j));
//System.out.println(a+" "+b);
sum = carry + a + b;
ans.append(""+(sum%10));
carry = sum/10;
}
if(i>=0){
for(;i>=0;i--){
int a = Integer.parseInt(""+num1.charAt(i));
sum = carry + a;
ans.append(""+(sum%10));
carry = sum/10;
}
}
if(j>=0){
for(;j>=0;j--){
int a = Integer.parseInt(""+num2.charAt(j));
sum = carry + a;
ans.append(""+(sum%10));
carry = sum/10;
}
}
if(carry!=0)ans.append(""+carry);
return ans.reverse().toString();
}
}
You can run the above code and see it works in all cases, this could be written in more compact way, but that would have been difficult to understand for you.
Hope it helps!
you can use this one that is independent of Integer or BigInteger methods
public String addStrings(String num1, String num2) {
int l1 = num1.length();
int l2 = num2.length();
if(l1==0){
return num2;
}
if(l2==0){
return num1;
}
StringBuffer sb = new StringBuffer();
int minLen = Math.min(l1, l2);
int carry = 0;
for(int i=0;i<minLen;i++){
int ind = l1-i-1;
int c1 = num1.charAt(ind)-48;
ind = l2-i-1;
int c2 = num2.charAt(ind)-48;
int add = c1+c2+carry;
carry = add/10;
add = add%10;
sb.append(add);
}
String longer = null;
if(l1<l2){
longer = num2;
}
else if(l1>l2){
longer = num1;
}
if(longer!=null){
int l = longer.length();
for(int i=minLen;i<l;i++){
int c1 = longer.charAt(l-i-1)-48;
int add = c1+carry;
carry = add/10;
add = add%10;
sb.append(add);
}
}
return sb.reverse().toString();
}
The method takes two string inputs representing non-negative integers and returns the sum of the integers as a string. The algorithm works by iterating through the digits of the input strings from right to left, adding each digit and any carryover from the previous addition, and appending the resulting sum to a StringBuilder. Once both input strings have been fully processed, any remaining carryover is appended to the output string. Finally, the string is reversed to produce the correct output order.
Hope this will solve the issue.!
public string AddStrings(string num1, string num2)
{
int i = num1.Length - 1, j = num2.Length - 1, carry = 0;
StringBuilder sb = new StringBuilder();
while (i >= 0 || j >= 0 || carry != 0) {
int x = i >= 0 ? num1[i--] - '0' : 0;
int y = j >= 0 ? num2[j--] - '0' : 0;
int sum = x + y + carry;
sb.Append(sum % 10);
carry = sum / 10;
}
char[] chars = sb.ToString().ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
Previous solutions have excess code. This is all you need.
class ShortStringSolution {
static String add(String num1Str, String num2Str) {
return Long.toString(convert(num1Str) + convert(num2Str));
}
static long convert(String numStr) {
long num = 0;
for(int i = 0; i < numStr.length(); i++) {
num = num * 10 + (numStr.charAt(i) - '0');
}
return num;
}
}
class LongStringSolution {
static String add(String numStr1, String numStr2) {
StringBuilder result = new StringBuilder();
int i = numStr1.length() - 1, j = numStr2.length() - 1, carry = 0;
while(i >= 0 || j >= 0) {
if(i >= 0) {
carry += numStr1.charAt(i--) - '0';
}
if(j >= 0) {
carry += numStr2.charAt(j--) - '0';
}
if(carry > 9) {
result.append(carry - 10);
carry = 1;
} else {
result.append(carry);
carry = 0;
}
}
if(carry > 0) {
result.append(carry);
}
return result.reverse().toString();
}
}
public class Solution {
static String add(String numStr1, String numStr2) {
if(numStr1.length() < 19 && numStr2.length() < 19) {
return ShortStringSolution.add(numStr1, numStr2);
}
return LongStringSolution.add(numStr1, numStr2);
}
}
For the sake of comprehension of the question
your method's name is addition
you are trying to do a power operation but the result is stored in a variable named multiplication...
there is more than one reason why that code doesnt work...
You need to do something like
Integer.parseInt(string)
in order to parse strings to integers
here the oficial doc

Extracting even digits from int

Here is the problem that I am solving.
Write a method evenDigits that accepts an integer parameter n and that
returns the integer formed by removing the odd digits from n. The
following table shows several calls and their expected return values:
Call Valued Returned
evenDigits(8342116); 8426
evenDigits(4109); 40
evenDigits(8); 8
evenDigits(-34512); -42
evenDigits(-163505); -60
evenDigits(3052); 2
evenDigits(7010496); 46
evenDigits(35179); 0
evenDigits(5307); 0
evenDigits(7); 0
If a negative number with even digits other than 0 is passed to the method, the result should also be negative, as shown above when -34512 is passed.
Leading zeros in the result should be ignored and if there are no even digits other than 0 in the number, the method should return 0, as shown in the last three outputs.
I have this so far -
public static int evenDigits(int n) {
    if (n != 0) { 
        int new_x = 0;
int temp = 0;
String subS = "";
    String x_str = Integer.toString(n);
if (x_str.substring(0, 1).equals("-")) {
 temp = Integer.parseInt(x_str.substring(0, 2));
 subS = x_str.substring(2);
} else {
 temp = Integer.parseInt(x_str.substring(0, 1));
 subS = x_str.substring(1);
}
        if (subS.length() != 0) {
             new_x = Integer.parseInt(x_str.substring(1));
        }
        
        if (temp % 2 == 0) {
             return Integer.parseInt((Integer.toString(temp) + evenDigits(new_x)));
        } else {
            return evenDigits(new_x);
        }
    }
return 0;
}
Why do people seem always to want to convert to String to deal with digits? Java has perfectly good arithmetic primitives for handling the job. For example:
public static int evenDigits(int n) {
int rev = 0;
int digitCount = 0;
// handle negative arguments
if (n < 0) return -evenDigits(-n);
// Extract the even digits to variable rev
while (n != 0) {
if (n % 2 == 0) {
rev = rev * 10 + n % 10;
digitCount += 1;
}
n /= 10;
}
// The digits were extracted in reverse order; reverse them again
while (digitCount > 0) {
n = n * 10 + rev % 10;
rev /= 10;
digitCount -= 1;
}
// The result is in n
return n;
}
Although it makes no difference for a simple academic exercise such as this one, handling the job via arithmetic alone can be expected to perform better than anything involving converting to String.
It's often easier to start with a recursive solution and then work you way back to iterative (if you must):
public static int evenDigits(int n) {
if (n < 0) {
return -evenDigits(-n);
} else if (n == 0) {
return 0;
} else if (n % 2 == 1) {
return evenDigits(n / 10);
} else {
return 10 * evenDigits(n / 10) + (n % 10);
}
}
int n = 8342116;
StringBuilder sb = new StringBuilder();
Integer.toString(n).chars()
.filter(x -> x % 2 == 0)
.mapToObj(i -> (char) i)
.forEachOrdered(sb::append);
int result = Integer.valueOf(sb.toString());
System.out.println(result); // 8426
public int evenDigits(int n) {
int r = 0;
boolean neg = false;
String evenDigits = "";
if (n < 0) { neg = true; n = abs(n); }
// keep dividing n until n = 0
while (n > 0) {
r = n % 10;
n = n / 10; // int division
if (r % 2 == 0) { evenDigits = Integer.toString(r) + evenDigits; }
}
int result = Integer.parseInt(evenDigits);
if (neg) { result -= 2 * result; }
return result;
}
This is more or less a pseudo code, but I think you get my idea. I have used this method for the same problem before.
A layman's solution that's based on Strings:
public static int evenDigits(int n) {
StringBuilder evenDigitsBuffer = new StringBuilder();
for (char digitChar : String.valueOf(n).toCharArray()) {
int digit = Character.getNumericValue(digitChar);
if (digit % 2 == 0) {
evenDigitsBuffer.append(digit);
}
}
return evenDigitsBuffer.length() > 0
? Integer.signum(n) * Integer.parseInt(evenDigitsBuffer.toString())
: 0;
}

Java Decimal To Binary - Big Numbers to Binary

My program should convert decimal numbers to binary. For big numbers it is giving me a negative number not a binary number. Why is this?
For example, if I supply 2321 I get 100100010001, which is fine. But if I supply
241242141 I get -2127232070093227171.
I can't use strings, arrays, functions. There is another option without define it as string? the output?
import java.util.Scanner;
public class d {
public static void main(String[] args) {
long num = 0;
long temp = 0L;
Scanner sc = new Scanner(System.in);
num = sc.nextLong();
long place = 1L;
long output = 0;
//System.out.print(""+ num%2+ (num%2)%2);
while(num != 0) {
temp = num % 2;
num = num / 2;
output += (place*temp);
place *=10;
}
System.out.print(""+output);
}
}
You problem is here
output += (place*temp);
place *=10;
this is producing a number which overflows.
A simple alternative is to create a String instead of generating a number you will convert to a String anyway.
StringBuilder output = new StringBuilder();
while(num != 0) {
output.append(num & 1);
num >>>= 1;
}
System.out.print(output.reverse());
or even
StringBuilder output = new StringBuilder();
for(long num = sc.netLong(); num != 0; num >>>= 1)
output.append(num & 1);
System.out.print(output.reverse());
If you want to use no functions except input or output.
long num = 241242141;
int shift = 63;
while (num >>> shift == 0 && shift > 0) shift--;
for (; shift >= 0; shift--)
System.out.print((num >>> shift) & 1);
// for comparison only
System.out.println("\n"+Long.toBinaryString(num));
prints
1110011000010001000000011101
1110011000010001000000011101
The problem is that, you are storing your Binary Equivalent in a long type, which cannot store such a long values.
You should rather use a StringBuilder and append your remainder - temp in it.
Then print it in reverse: -
StringBuilder builder = new StringBuilder();
while(num != 0) {
temp = num % 2;
num = num / 2;
builder.append(temp);
output += (place*temp);
place *=10;
}
System.out.println(builder.reverse());
If you don't need to use any methods, then just use String Concatenation, and then a loop to print the string in reverse: -
String builder = "";
while(num != 0) {
temp = num % 2;
num = num / 2;
builder += temp;
output += (place*temp);
place *=10;
}
for (int i = builder.length() - 1; i >= 0; i--) {
System.out.print(builder.charAt(i));
}
But, beware, this will create a large number of String objects on Heap. Also, here you are using a charAt method, that you have to use.
With recursion:
public class d {
static void toBinaryString( long number )
{
if( number > 1 ) toBinaryString( number / 2L );
System.out.print( number % 2L );
}
public static void main(String[] args) {
long num = 241242141L;
System.out.println( Long.toBinaryString( num ));
toBinaryString( num );
}
}
The ouput:
1110011000010001000000011101
1110011000010001000000011101

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