Optimization of a Java code - java

This is a code in an online contest I've been trying. The time limit set at the online judge is 1 sec and the order of test cases is 10^5.
import java.util.Scanner;
class My_Number {
int primeNo;
boolean divisible[] = new boolean [60];
My_Number(int primeNo) {
this.primeNo = primeNo;
}
void setDivisible() {
for (int i=0; i<60; i++) {
if(i%primeNo == 0) {
divisible[i] = true;
}
}
}
}
class BestWorse {
My_Number gb [] = {
new My_Number(2), new My_Number(3), new My_Number(5), new My_Number(7), new My_Number(11),
new My_Number(13), new My_Number(17), new My_Number(19), new My_Number(23), new My_Number(29),
new My_Number(31), new My_Number(37), new My_Number(41), new My_Number(43), new My_Number(47),
new My_Number(53), new My_Number(59)
};
boolean master_list [] = new boolean [86400];
void initialize() {
for (My_Number gb1 : gb) {
gb1.setDivisible();
}
}
private boolean isBad(int hh, int mm, int ss) {
for(My_Number gb1: gb) {
if(gb1.divisible[hh] && gb1.divisible[mm] && gb1.divisible[ss]) {
return true;
}
}
return false;
}
private int findGCD(int a, int b) {
int r, i;
while(b!=0){
r = a % b;
a = b;
b = r;
}
return a;
}
void fillUpTheMasterList() {
int hh =0, mm = 0, ss = 1;
while( !(hh==0 && ss==0 && mm==0)) {
if (isBad(hh, mm, ss)) {
master_list[hh*60*60+mm*60+ss] = true;
}
ss++;
if(ss == 60) {
ss = 0;
mm++;
if(mm == 60) {
mm = 0;
hh++;
if(hh == 24) {
hh = 0;
}
}
}
}
}
String countBestAndWorse(int hh, int mm, int ss) {
int good = 0, bad = 0;
for(int i=hh*60*60+mm*60+ss; i<86400; i++) {
if(master_list[i]) {
bad++;
}
else {
good++;
}
}
if(good != 0 && bad != 0)
{
int gcd = findGCD(good, bad);
good /= gcd;
bad /= gcd;
}
return bad + ":" +good;
}
public static void main(String[]args) {
int n;
Scanner scn = new Scanner(System.in);
BestWorse best_worse = new BestWorse();
best_worse.initialize();
best_worse.fillUpTheMasterList();
n = scn.nextInt();
for(int i=0; i<n;i++) {
int hh = scn.nextInt();
int mm = scn.nextInt();
int ss = scn.nextInt();
System.out.println(best_worse.countBestAndWorse(hh, mm, ss));
}
}
}
For some reason, I am continuously getting the error as 'Time limit exceeded'.
Things I tried:
Using BufferedReader instead of Scanner
Maintaining a master_list of the answer(already implemented in my solution).
I tried the Netbeans profiler and it's output for input of 5000 (hh=0 mm=0 ss=1) numbers is pasted here. Also, the question is posted here.
From the profiler, it seems like findGCD is taking up majority of the time. But I googled around and found out that this is indeed the fastest algorithm to calculate GCD. I also tried to maintain a lookup table for GCD; perhaps the same GCD is calculated again and again. Still no luck!
I've reached my limit for this question and need help. Can anyone please help me out here?

Its all about using the correct algorithm.
Check out this approach:
import java.util.Scanner;
public class GoodBadTime
{
private int goodTimeCounter[][][];
private int badTimeCounter[][][];
private static final int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
public GoodBadTime ()
{
initializeGoodBadTimes ();
try (Scanner scanner = new Scanner (System.in))
{
int testCases = scanner.nextInt ();
for (int i = 0; i < testCases; ++i)
{
int h = scanner.nextInt ();
int m = scanner.nextInt ();
int s = scanner.nextInt ();
System.out.println (badTimeCounter[h][m][s] + ":" + goodTimeCounter[h][m][s]);
}
}
}
private void initializeGoodBadTimes ()
{
goodTimeCounter = new int[24][60][60];
badTimeCounter = new int[24][60][60];
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
boolean isBadTime = false;
int prime;
for (int p = 0; p < primes.length && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = true;
break;
}
}
if (isBadTime)
{
++cumulativeBadCounter;
}
else
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
goodTimeCounter[h][m][s] = cumulativeGoodCounter / gcd;
badTimeCounter[h][m][s] = cumulativeBadCounter / gcd;
}
}
}
}
private int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
public static void main (String[] args)
{
new GoodBadTime ();
}
}
Let me know if there's something I need to explain in my code that isn't obvious, so that I can edit my answer and explain it to you.
This was just my first attempt to solve it, there can be better ways to do it as well.
But this approach should give out the output within 1 second, so I guess, I don't cross the threshold limit with this approach.
Update
Here's an update to the answer:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GoodBadTime
{
private int goodTimeCounter[];
private int badTimeCounter[];
private static final int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
public GoodBadTime ()
{
initializeGoodBadTimes ();
try (BufferedReader reader = new BufferedReader (new InputStreamReader (System.in)))
{
int testCases = Integer.parseInt (reader.readLine ());
for (int i = testCases; i > 0; --i)
{
String[] hms = reader.readLine ().split ("\\s+");
int h = Integer.parseInt (hms[0]);
int m = Integer.parseInt (hms[1]);
int s = Integer.parseInt (hms[2]);
int index = h + 24 * (m + 60 * s);
System.out.printf ("%d:%d\n", badTimeCounter[index], goodTimeCounter[index]);
}
}
catch (IOException e)
{
e.printStackTrace ();
}
}
private void initializeGoodBadTimes ()
{
goodTimeCounter = new int[24 * 60 * 60];
badTimeCounter = new int[24 * 60 * 60];
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
boolean isBadTime = false;
int prime;
for (int p = 0; p < primes.length && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = true;
++cumulativeBadCounter;
break;
}
}
if (!isBadTime)
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
// Original[h, m, s] = Flat[h + 24 * (m + 60 * s)]
int index = h + 24 * (m + 60 * s);
goodTimeCounter[index] = cumulativeGoodCounter / gcd;
badTimeCounter[index] = cumulativeBadCounter / gcd;
}
}
}
}
private int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
public static void main (String[] args)
{
new GoodBadTime ();
}
}
This should be faster than the previous one, since I'm using 1D array and BufferedReader this time.
Here's a C equivalent:
#include <stdio.h>
int goodTimeCounter[24 * 60 * 60];
int badTimeCounter[24 * 60 * 60];
const int primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
int GCD (int p, int q)
{
if (p == 0 || q == 0)
{
return 1;
}
while (q != 0)
{
int temp = q;
q = p % q;
p = temp;
}
return p;
}
void initializeGoodBadTimes ()
{
int cumulativeGoodCounter = 0;
int cumulativeBadCounter = 0;
for (int h = 23; h >= 0; --h)
{
for (int m = 59; m >= 0; --m)
{
for (int s = 59; s >= 0; --s)
{
int isBadTime = 0;
int prime;
for (int p = 0; p < 9 && ((prime = primes[p]) <= h); ++p)
{
if (h % prime == 0 && m % prime == 0 && s % prime == 0)
{
isBadTime = 1;
++cumulativeBadCounter;
break;
}
}
if (!isBadTime)
{
++cumulativeGoodCounter;
}
int gcd = GCD (cumulativeGoodCounter, cumulativeBadCounter);
// Original[h, m, s] = Flat[h + 24 * (m + 60 * s)]
int index = h + 24 * (m + 60 * s);
goodTimeCounter[index] = cumulativeGoodCounter / gcd;
badTimeCounter[index] = cumulativeBadCounter / gcd;
}
}
}
}
int main (int argc, const char * argv[])
{
initializeGoodBadTimes();
int testCases;
scanf("%d", &testCases);
for(int i = testCases; i > 0; --i)
{
int h, m, s;
scanf("%d %d %d", &h, &m, &s);
int index = h + 24 * (m + 60 * s);
printf("%d:%d\n", badTimeCounter[index], goodTimeCounter[index]);
}
return 0;
}
Note: GCD is calculated constant number of times, irrespective of the input size.
Also, int is sufficient for this program, since no counter ever exceeds 86400 since that's the maximum number of good or bad times that can happen.
Its equally strange for me that Online Judge is calling it as "Wrong Answer", since I think I am following every constraint set by the question.
Also, while testing for the two inputs, the program gave the correct answer despite the input being far apart in time. Induction would say that it should keep giving correct answers. Do you happen to know which output is wrong?
Also, can you put a link to this question which is present on the Online Judge site, so that I can check it out myself, and provide a correct answer to you?

The contest is rather unclear; at least to me. It says "none of them was divisible by the same prime number" which makes no sense, and if it did, I'd interpret it as that all the numbers must be co-prime. The next sentence sounds more like gcd(h, gcd(m, s)) <= 1 for good days.
I'm offering some untested potential improvements to Aman Agnihotri's algorithms. By creating the cumulative table, the biggest optimization is already done.
There is a faster GDC algorithm, but I wouldn't bother as all you need is to fill a 60x60 table. This could be done even without GCD by something like
int[] gcdTable = new int[60*60];
Arrays.fill(gcdTable, 1);
for (int p=2; p<60; ++p)
for (int i=0; i<60; i+=p)
for (int j=0; j<60; j+=p)
gcdTable[60*i+j] = Math.max(gcdTable[60*i+j], p);
Then use it as
int gcd(int a, int b) {
return gcdTable[60*a+b];
}
in
boolean isGood(int h, int m, int s) {
return gcd(h, gcd(m, s)) <= 1;
}
to fill the cumulative table. I guess, using a 1D array via
int secondOfDay(int h, int m, int s) {
return 3600*h + 60*m + s;
}
should be a bit faster than a 3D array. You don't need to store both remaining good and bad seconds, as their sum equals to 24*3600 - secondOfDay. My above table is too small for use for the expressing of the B:G ratio in smallest common terms, so you'll need one proper GCD per sample.

Related

How to count happy numbers

As an assignment I need to count the amount of happy numbers* in a given range. I did most of that already:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String inputLowerRange = scan.nextLine().trim();
String inputUpperRange = scan.nextLine().trim();
int lowerRange = Integer.parseInt(inputLowerRange);
int upperRange = Integer.parseInt(inputUpperRange);
Set<Integer> numbers = new HashSet<Integer>();
for (int i = lowerRange; i <= upperRange; i++)
while(lowerRange>0) {
upperRange += (lowerRange % 10)*(lowerRange % 10);
lowerRange /=10;
}
int counter = 0;
for (int i = lowerRange; i <= upperRange; i++) {
}
System.out.println(counter);
}
}
Now the code just needs to count the happy numbers* present within that range. I understand it is best done with:
if ............... counter++
but how exactly would I need to do it?
*A happy number is a number which eventually reaches 1 when replaced by the sum of the square of each digit. 13 is a happy number because 1^2 + 3^2 = 10
And 1^2 + 0^2 = 1, thus 13 is a happy number.
int counter = 0;
for(int i=lowerRange;i<=upperRange;i++)
{
int num=i,sum=0,rem;
while(sum!=1 && sum!=4)
{
sum=0;
while(num!=0)
{
rem=num%10;
sum+=(rem*rem);
num/=10;
}
num=sum;
}
if(sum==1)
counter++
}
System.out.println(counter);
the issue with your code is you are making direct changes to lowerRange and upperRange which will result in not iterating properly. You need to use temp variables for those. Also you forgot this condition while(sum!=1 && sum!=4){}
Set<Integer> numbers = new HashSet<Integer>(); //what's this for?
for (int i = lowerRange; i <= upperRange; i++)
while(lowerRange>0) { // missed one outer while loop
upperRange += (lowerRange % 10)*(lowerRange % 10); // changes to upperRange
lowerRange /=10; // changes to lowerRange
}
Try this.
static boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while (n > 1 && !set.contains(n)) {
set.add(n);
n = String.valueOf(n).chars()
.map(c -> c - '0')
.reduce(0, (sum, i) -> sum + i * i);
}
return n == 1;
}
public static void main(String args[]) throws IOException {
Scanner scan = new Scanner(System.in);
System.out.println(IntStream.rangeClosed(scan.nextInt(), scan.nextInt())
.filter(i -> isHappy(i))
.count());
}
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
System.out.println(isHappy(null, 11));
}
public static boolean isHappy(Set<Integer> previousNumbers, int number) {
if (previousNumbers == null) previousNumbers = new HashSet<>();
else if (previousNumbers.contains(number)) return false;
if (number == 4) return true;
int length = getNumberLength(number);
int subNumber = 0;
for (int i = 0; i < length; i++) {
int digit = getNumberDigit(number, i);
subNumber += digit * digit;
}
previousNumbers.add(number);
return isHappy(previousNumbers, subNumber);
}
public static int getNumberDigit(int number, int index) {
int pow = (int) Math.pow(10, index);
return (number % (pow * 10)) / pow;
}
public static int getNumberLength(int number) {
int length = 0;
for (long temp = 1; temp <= number; temp *= 10)
length++;
return length;
}
}

Bloom Filters: Getting higher error rates than expected

I created a bloom filter using murmur3, blake2b, and Kirsch-Mitzenmacher-optimization, as described in the second answer to this question: Which hash functions to use in a Bloom filter
However, when I was testing it, the bloom filter constantly had a much higher error rate than I was expecting.
Here is the code I used to generate the bloom filters:
public class BloomFilter {
private BitSet filter;
private int size;
private int hfNum;
private int prime;
private double fp = 232000; //One false positive every fp items
public BloomFilter(int count) {
size = (int)Math.ceil(Math.ceil(((double)-count) * Math.log(1/fp))/(Math.pow(Math.log(2),2)));
hfNum = (int)Math.ceil(((this.size / count) * Math.log(2)));
//size = (int)Math.ceil((hfNum * count) / Math.log(2.0));
filter = new BitSet(size);
System.out.println("Initialized filter with " + size + " positions and " + hfNum + " hash functions.");
}
public BloomFilter extraSecure(int count) {
return new BloomFilter(count, true);
}
private BloomFilter(int count, boolean x) {
size = (int)Math.ceil((((double)-count) * Math.log(1/fp))/(Math.pow(Math.log(2),2)));
hfNum = (int)Math.ceil(((this.size / count) * Math.log(2)));
prime = findPrime();
size = prime * hfNum;
filter = new BitSet(prime * hfNum);
System.out.println("Initialized filter with " + size + " positions and " + hfNum + " hash functions.");
}
public void add(String in) {
filter.set(getMurmur(in), true);
filter.set(getBlake(in), true);
if(this.hfNum > 2) {
for(int i = 3; i <= (hfNum); i++) {
filter.set(getHash(in, i));
}
}
}
public boolean check(String in) {
if(!filter.get(getMurmur(in)) || !filter.get(getBlake(in))) {
return false;
}
for(int i = 3; i <= hfNum; i++) {
if(!filter.get(getHash(in, i))) {
return false;
}
}
return true;
}
private int getMurmur(String in) {
int temp = murmur(in) % (size);
if(temp < 0) {
temp = temp * -1;
}
return temp;
}
private int getBlake(String in) {
int temp = new BigInteger(blake256(in), 16).intValue() % (size);
if(temp < 0) {
temp = temp * -1;
}
return temp;
}
private int getHash(String in, int i) {
int temp = ((getMurmur(in)) + (i * getBlake(in))) % size;
return temp;
}
private int findPrime() {
int temp;
int test = size;
while((test * hfNum) > size ) {
temp = test - 1;
while(!isPrime(temp)) {
temp--;
}
test = temp;
}
if((test * hfNum) < this.size) {
test++;
while(!isPrime(test)) {
test++;
}
}
return test;
}
private static boolean isPrime(int num) {
if (num < 2) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2)
if (num % i == 0) return false;
return true;
}
#Override
public String toString() {
final StringBuilder buffer = new StringBuilder(size);
IntStream.range(0, size).mapToObj(i -> filter.get(i) ? '1' : '0').forEach(buffer::append);
return buffer.toString();
}
}
Here is the code I'm using to test it:
public static void main(String[] args) throws Exception {
int z = 0;
int times = 10;
while(z < times) {
z++;
System.out.print("\r");
System.out.print(z);
BloomFilter test = new BloomFilter(4000);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
for(int i = 0; i < 4000; i++) {
test.add(blake256(Integer.toString(random.nextInt())));
}
int temp = 0;
int count = 1;
while(!test.check(blake512(Integer.toString(temp)))) {
temp = random.nextInt();
count++;
}
if(z == (times)) {
Files.write(Paths.get("counts.txt"), (Integer.toString(count)).getBytes(), StandardOpenOption.APPEND);
}else {
Files.write(Paths.get("counts.txt"), (Integer.toString(count) + ",").getBytes(), StandardOpenOption.APPEND);
}
if(z == 1) {
Files.write(Paths.get("counts.txt"), (Integer.toString(count) + ",").getBytes());
}
}
}
I expect to get a value relatively close to the fp variable in the bloom filter class, but instead I frequently get half that. Anyone know what I'm doing wrong, or if this is normal?
EDIT: To show what I mean by high error rates, when I run the code on a filter initialized with count 4000 and fp 232000, this was the output in terms of how many numbers the filter had to run through before it found a false positive:
158852,354114,48563,76875,156033,82506,61294,2529,82008,32624
This was generated using the extraSecure() method for initialization, and repeated 10 times to generate these 10 numbers; all but one of them took less than 232000 generated values to find a false positive. The average of the 10 is about 105540, and that's common no matter how many times I repeat this test.
Looking at the values it found, the fact that it found a false positive after only generating 2529 numbers is a huge issue for me, considering I'm adding 4000 data points.
I'm afraid I don't know where the bug is, but you can simplify a lot. You don't actually need prime size, you don't need SecureRandom, BigInteger, and modulo. All you need is a good 64 bit hash (seeded if possible, for example murmur):
long bits = (long) (entryCount * bitsPerKey);
int arraySize = (int) ((bits + 63) / 64);
long[] data = new long[arraySize];
int k = getBestK(bitsPerKey);
void add(long key) {
long hash = hash64(key, seed);
int a = (int) (hash >>> 32);
int b = (int) hash;
for (int i = 0; i < k; i++) {
data[reduce(a, arraySize)] |= 1L << index;
a += b;
}
}
boolean mayContain(long key) {
long hash = hash64(key, seed);
int a = (int) (hash >>> 32);
int b = (int) hash;
for (int i = 0; i < k; i++) {
if ((data[reduce(a, arraySize)] & 1L << a) == 0) {
return false;
}
a += b;
}
return true;
}
static int reduce(int hash, int n) {
// http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
return (int) (((hash & 0xffffffffL) * n) >>> 32);
}
static int getBestK(double bitsPerKey) {
return Math.max(1, (int) Math.round(bitsPerKey * Math.log(2)));
}
Turns out the issue was that the answer on the other page wasn't completely correct, and neither was the comment below it.
The comment said:
in the paper hash_i = hash1 + i x hash2 % p, where p is a prime, hash1 and hash2 is within range of [0, p-1], and the bitset consists k * p bits.
However, looking at the paper reveals that while all the hashes are mod p, each hash function is assigned a subset of the total bitset, which I understood to mean hash1 mod p would determine a value for indices 0 through p, hash2 mod p would determine a value for indices p through 2*p, and so on and so forth until the k value chosen for the bitset is reached.
I'm not 100% sure if adding this will fix my code, but it's worth a try. I'll update this if it works.
UPDATE: Didn't help. I'm looking into what else may be causing this problem.

Generating vampire numbers in free range

I am writing program which generates Vampire numbers https://en.wikipedia.org/wiki/Vampire_number.
I have main function with numberOfDigits argument, which must be even. If numberOfDigits is equal 4, then we are searching Vampire Numbers in range 1000 to 9999 - four digits. If numberOfDigits is equal 6, then we are searching Vampire Numbers from 100000 to 999999 - which is six digits.
In following file, when I want to search Vampire numbers in range of 10 digits, Java heap space is screaming. Note that I have default settings for memory. But for, numberOfDigits == 4, 6 or 8, code is working correctly. (compared output to https://oeis.org/A014575/b014575.txt , https://oeis.org/A014575 ). So I want to ask,
What I can do to optimize this code? I have thought about using String with digits inside, instead of long/BigInteger. I want to "omit" that heap problem. Saving big numbers to file would be too slow, am I right?
My mate wrote (bigNum.cpp) http://pastebin.com/0HHdE848 - class in C++, to operate on big numbers. Maybe with help from community I could implement that in my a.java? More important - would it be useful for my problem?
edit: My goal is to generate free range of Vampire Numbers, like 4,6,8 - a.java it can do it, even more (if I can bypass heap space problem). And that is when my questions to help comes.
a.java (permutation code from johk95, https://stackoverflow.com/a/20906510 )
import java.util.ArrayList;
import java.util.Arrays;
/**
*
* #author re
*/
public class a {
/**
*
* #param numberOfDigits {int}
* #return ArrayList of Integer
*/
public ArrayList<Integer> vdf(int numberOfDigits) {
if ((numberOfDigits % 2) == 1) {
//or throw Exception of unrecognised format/variable?
System.out.println("cant operate on odd argument");
return new ArrayList<>();
}
long maxRange = 9;
for (int i = 1; i < numberOfDigits; i++) {
maxRange *= 10;
maxRange += 9;
}//numberOfDigits==4 then maxRange==9999, nOD==5 then maxRange==99999,..
long minRange = 1;
for (int i = 1; i < numberOfDigits; i++) {
minRange *= 10;
}//nOD==4 then minRange==1000, nOD==5 then minRange==10000, ..
ArrayList<Integer> ret = new ArrayList<>();
for (long i = minRange; i < maxRange; i++) {
long a = i;
long[] b = new long[numberOfDigits];
for (int j = numberOfDigits-1; j >= 0 ; j--) {
long c = a % 10;
a = a / 10;
b[j] = c;
}
int x = 0;
int y = 0;
ArrayList<long[]> list = permutations(b);
b = null; //dont need now
for(long[] s : list) {
for (int j = 0; j < numberOfDigits/2; j++) {
x += s[(numberOfDigits/2)-j-1] * Math.pow(10, j);
y += s[numberOfDigits-j-1] * Math.pow(10, j);
}
StringBuilder builder = new StringBuilder();
for (long t : s) {
builder.append(t);
}
String v = builder.toString();
if ((v.charAt((v.length()/2)-1) != '0'||
v.charAt(v.length()-1) != '0') &&
x * y == i) {
ret.add(x);
ret.add(y);
System.out.println(x*y+" "+x+" "+y);
break;
}
x = y = 0;
}
}
System.out.printf("%d vampire numbers found\n", ret.size()/2);
return ret;
}
/**
*
*#return vdf(4)
*/
public ArrayList<Integer> vdf() {
return vdf(4);//without trailing zeros
}
/* permutation code copied from
* johk95
* https://stackoverflow.com/a/20906510
*/
private static ArrayList<long[]> permutations(long[] lol) {
ArrayList<long[]> ret = new ArrayList<>();
permutation(lol, 0, ret);
return ret;
}
private static void permutation(long[] arr, int pos, ArrayList<long[]> list){
if(arr.length - pos == 1)
list.add(arr.clone());
else
for(int i = pos; i < arr.length; i++){
swap(arr, pos, i);
permutation(arr, pos+1, list);
swap(arr, pos, i);
}
}
private static void swap(long[] arr, int pos1, int pos2){
long h = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = h;
}
public static void main(String[] args) {
a a = new a();
try{
a.vdf(10); //TRY IT WITH 4, 6 or 8. <<<<
}catch (java.lang.OutOfMemoryError e){
System.err.println(e.getMessage());
}
}
}
EDIT: http://ideone.com/3rHhep - working code above with numberOfDigits == 4.
package testing;
import java.util.Arrays;
public class Testing
{
final static int START = 11, END = 1000;
public static void main(String[] args)
{
char[] kChar, checkChar;
String kStr, checkStr;
int k;
for(int i=START; i<END; i++) {
for(int i1=i; i1<100; i1++) {
k = i * i1;
kStr = Integer.toString(k);
checkStr = Integer.toString(i) + Integer.toString(i1);
//if(kStr.length() != 4) break;
kChar = kStr.toCharArray();
checkChar = checkStr.toCharArray();
Arrays.sort(kChar);
Arrays.sort(checkChar);
if(Arrays.equals(kChar, checkChar)) {
System.out.println(i + " * " + i1 + " = " + k);
}
}
}
}
}
This will generate vampire numbers, just modify the start and end integers.

Difference of Opinion for Counts

I made 2 small scripts in physics today, but now it is starting to bug me.
The first script, is 100% accurate: It is used to calculate the number of bill and coins required for the desired amount of cash.
First Script:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Change {
static Money[] coins;
static int[] counts;
public static void main(String[] args) throws IOException {
coins = new Money[11];
counts = new int[11];
coins[0] = new Money(100);
coins[1] = new Money(50);
coins[2] = new Money(20);
coins[3] = new Money(10);
coins[4] = new Money(5);
coins[5] = new Money(2);
coins[6] = new Money(1);
coins[7] = new Money(25, true);
coins[8] = new Money(10, true);
coins[9] = new Money(5, true);
coins[10] = new Money(1, true);
System.out.println("Please type the change:\n");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String values = br.readLine();
String[] split = values.split("\\.");
System.out.println();
int whole = Integer.parseInt(split[0]);
int small = Integer.parseInt(split[1]);
for (int i = 0; i < 7; i++) {
while (whole >= coins[i].getValue()) {
whole -= coins[i].getValue();
counts[i]++;
}
}
for (int i = 7; i < 11; i++) {
while (small >= coins[i].getValue()) {
small -= coins[i].getValue();
counts[i]++;
}
}
for (int i = 0; i < 11; i++) {
if (counts[i] > 0)
System.out
.println((coins[i].getValue() == 100 ? "" : " ")
+ (coins[i].isDecimal() ? (" 0."
+ (coins[i].getValue() < 10 ? "0" : "") + coins[i]
.getValue()) + ": " + counts[i]
: ((coins[i].getValue() <= 5 ? " " : "") + coins[i]
.getValue())
+ ".00: "
+ counts[i]));
}
}
public static class Money {
int value;
boolean decimal;
Money(int value) {
this(value, false);
}
Money(int value, boolean decimal) {
this.value = value;
this.decimal = decimal;
}
boolean isDecimal() {
return decimal;
}
int getValue() {
return value;
}
}
}
Second script:
import java.io.IOException;
public class ChangeMax {
static Money[] coins;
static int[] nums = new int[2];
static int max = -2147483648;
public static void main(String[] args) throws IOException{
coins = new Money[11];
coins[0] = new Money(100);
coins[1] = new Money(50);
coins[2] = new Money(20);
coins[3] = new Money(10);
coins[4] = new Money(5);
coins[5] = new Money(2);
coins[6] = new Money(1);
coins[7] = new Money(25, true);
coins[8] = new Money(10, true);
coins[9] = new Money(5, true);
coins[10] = new Money(1, true);
for(int i = 0; i < 100; i++){
int temp1 = i;
for(int h = 1; h < 100; h++){
int temp2 = h;
int[] counts = new int[100];
for (int j = 0; j < 7; j++) {
while (temp1 >= coins[j].getValue()) {
temp1 -= coins[j].getValue();
counts[j]++;
}
}
for (int k = 7; k < 11; k++) {
while (temp2 >= coins[k].getValue()) {
temp2 -= coins[k].getValue();
counts[k]++;
}
}
int sum = 0;
for(int p : counts){
sum += p;
}
if(sum > max){
max = sum;
nums[0] = i;
nums[1] = h;
}
}
}
System.out.println("\nMax coins and bills required at: $"+nums[0]+"."+(nums[1] > 9 ? nums[1] : "0" + nums[1]) + ": "+max+"\n");
}
public static class Money {
int value;
boolean decimal;
Money(int value) {
this(value, false);
}
Money(int value, boolean decimal) {
this.value = value;
this.decimal = decimal;
}
boolean isDecimal() {
return decimal;
}
int getValue() {
return value;
}
}
}
The second script, does the same thing, but runs through all the values under $100.
The problem is, is that the second script says the max amount is 9, and achieved at $0.94.
The first, script, when you type something like $1.94, does not register that 10 is the new highest number, instead of 9.
What seems to be the problem?
Since I am not planning on doing your homework I am not going to provide you with working code, but both scripts can be easily improved
1) Your money objects know whether a value of e.g. 10 represents 10 whole dollars, or 10 cents (or whatever you use in America, I would use Euro's and cents). But still you use an hard-coded index of your array where you switch from dollars to cents
2) The first script will fail when somebody uses a nice rounded number as input, without decimal part
3) If you would convert your input first to cents, and all your values in your coin array as well, your code will end up much cleaner and easier to understand. Something in the form of
int startAmount = ... ;//in cents
int remainder = startAmount;
int coinCounter = new int[coins.length];
for ( int i = 0; i < coins.length; i++ ){
int currentCoin = coins[i];//in cents
coinCointer[i] = 0;
while( remainder >= currentCoin ){
coinCointer[i] = coinCointer[i] + 1;
remainder = remainder - currentCoin;
}
}
//print out by looping over coinCounter,
//and use the info contained in the Money class

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