Related
I am trying to multiply each "column" of an array by a specific number, and then sum up the results for each "row".
I was able to figure out how to do this for a single array, but I am having trouble figuring this out for a 2d-array.
I need to do this recursively, so no loops. Can anybody provide a pseudocode, or explain what steps I should be taking for each column?
public static int didIt(int[] d, int n) {
//base or terminating condition
if (n <= 0) {
return 0;
}
if (n == 1) {
return didIt(d, n - 1) + d[n - 1] * 10;
}
if (n == 2) {
return didIt(d, n - 1) + d[n - 1] * 50;
}
if (n == 3) {
return didIt(d, n - 1) + d[n - 1] * 22;
}
if (n == 4) {
return didIt(d, n - 1) + d[n - 1] * 7;
}
if (n == 5) {
return didIt(d, n - 1) + d[n - 1] * 45;
} else {
return didIt(d, n - 1) + d[n - 1];
}
}
public static void main(String[] args) {
int[] array2 = {1, 2, 3, 4, 5};
System.out.println(didIt(array2, array2.length));
}
How would I turn this code into a 2d-array version?
Update
Since you need every "row" to be treated in the same way you can recursively add up the total calculated for every nested array by moving position in the matrix with every recursive call:
public static int arrSum(int[] arr, int pos) {
if (pos == arr.length) { // base case
return 0;
}
return arr[pos] + arrSum(arr, pos + 1); // recursive case
}
Your condition logic can be brushed up like that:
public static int arrSum(int[] arr, int pos) {
if (pos == arr.length) { // base case
return 0;
}
if (pos == 0) {
return 10 * arr[pos] + arrSum(arr, pos + 1);
}
if (pos == 1) {
return 50 * arr[pos] + arrSum(arr, pos + 1);
}
if (pos == 2) {
return 22 * arr[pos] + arrSum(arr, pos + 1);
}
if (pos == 3) {
return 7 * arr[pos] + arrSum(arr, pos + 1);
}
if (pos == 4) {
return 45 * arr[pos] + arrSum(arr, pos + 1);
}
return arr[pos] + arrSum(arr, pos + 1);
}
This part is related to the Initial version of the Question
You don't need redundant conditional logic repeated for every hard-coded value of n.
As well as there's no need to multiply each element of the array by 10, instead we can multiply by 10 the overall sum.
That's how your recursive method that calculates the array sum can be fixed:
public static int arrSum(int[] arr, int pos) {
if (pos == arr.length) { // base case
return 0;
}
return arr[pos] + arrSum(arr, pos + 1); // recursive case
}
And that how you can calculate the sum of the elements of a nested array (the logic is almost the same):
public static int matrixSum(int[][] matrix, int pos) {
if (pos == matrix.length) { // base case
return 0;
}
return arrSum(matrix[pos], 0) + matrixSum(matrix, pos + 1); // recursive case
}
main()
public static void main(String[] args) {
int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
System.out.println(matrixSum(matrix, 0) * 10);
}
Output:
450 // sum of numbers from 1 to 9 equels 45, and * 10 = 450
Sidenote: in Java there's no 2d-arrays (so this term isn't correct accurate). We can create a nested array - an array that is composed of other arrays.
You can still use same logic; just change how you can call your didIt method:
public static void main(String[] args) {
int[][] arr = { { 1, 1, 1, 1 },
{ 2, 2, 2, 2 },
{ 3, 3, 3, 3 } };
for(int a[]: arr) {
System.out.print(didIt(a,a.length));
}
No need to change anything in didIt.
Also, I assume your didIt which you showed here is for demonstraion purpose, otherwise there is plenty of repeated code in if which you can able to avoid.
Question: given an array, you need to find 3 elements inside the array that will give the biggest product of all when multiplied.
For example, given the following input:
-4, 1, -8, 9, 6
...the expected output is -4, -8, 9, as -4 * -8 * 9 == 288.
you can assume that there are no nulls inside the array.
signature must be public static int findTriplet(int[] a);.
my code:
public static int findTriplet(int[] a) {
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE,
maxLowby2 = Integer.MIN_VALUE, maxLowby1 = Integer.MIN_VALUE,
secondMin = Integer.MAX_VALUE, minIndex = -1, maxIndex = -1, indexofLowby1 = -1;
//we run a for loop to go over the array and collect all our needed information.
for (int i = 0; i < a.length; i++) {
//first we find the smallest value
if (min > a[i] && a[i] < 0) {
min = a[i];
minIndex = i;// we save the index so we can find other num that is negative and is different from this 1
////here we try to find the second smallest num in the array in such that it has to be a minus otherwise we wont be able to get a popsitive number(-1*-1=positive)
//if the index is different and second Min is smaller then the value in a[i] and a[i] must be a negetive num;
} else if (minIndex != i && secondMin > a[i] && a[i] < 0) {
secondMin = a[i];
}
//
if (max < a[i]) {
max = a[i];
maxIndex = i;
//now we look for only positive numbers
//here we need to find two other sumbers that are the biggest in the array but are different then each other.
} else if (max > a[i] && a[i] >= 0 && maxLowby1 < a[i] && maxIndex != i) {
maxLowby1 = a[i];
indexofLowby1 = i;
//here we find the last positive number that will be smaller the max and maxlowBy1
} else if (a[i] >= 0 && indexofLowby1 != i)
maxLowby2 = a[i];
}
// we creat the needed numbers and return the max value of them.
int finalMax = max * maxLowby2 * maxLowby1;
int secondMinus = max * min * secondMin;
return Math.max(finalMax, secondMinus);
} ```
If you only need to keep track of three values it's pretty easy to avoid inner loops. Keep track of the positives and negatives separately. You'll only need to keep track of the two smallest negatives.
Compare each new number against the previously known values. By falling through you determine where to slide values down (in terms of absolute value) and insert the new one.
The special case of three values is treated distinctly. All three initial values are captured separately and only used in this instance. This does assume there are at least three values in the list.
n1 = n2 = p1 = p2 = p3 = 0; // negatives / positives with largest abs()
m3 = m2 = m1 = int.minValue; // store for case when only three values
for(i = 0; i < a.length; i++) {
m = a[i];
if (m > p3) { p1 = p2; p2 = p3; p3 = m; }
else if (m > p2) { p1 = p2; p2 = m; }
else if (m > p1) { p1 = m; }
else if (m < n2) { n1 = n2; n2 = m; }
else if (m < n1) { n1 = m; }
switch (i)
case 1 : m1 = m; break;
case 2 : m2 = m; break;
case 3 : m3 = m; break;
}
l = a.length;
if (l < 3) { v = 0; } // error?
else if (l == 3) { v = m1 * m2 * m3; }
else if (n1 * n2 > p1 * p2) { v = n1 * n2 * p3; }
else { v = p1 * p2 * p3; }
return v;
Consider it to be pseudocode rather than proper Java.
https://www.online-python.com/Hreut5EWav
Below is essentially QuinncyJones's more compact logic but without the sort operation. And I reduced the number of variables involved aseell.:
n1 = n2 = 0; // two smallest negatives
m3 = m2 = m1 = int.minValue; // three largest values regardless of sign
for(i = 0; i < a.length; i++) {
m = a[i];
if (m > m3) { m1 = m2; m2 = p3; m3 = m; }
else if (m > m2) { m1 = m2; m2 = m; }
else if (m > m1) { m1 = m; }
if (m < n2) { n1 = n2; n2 = m; }
else if (m < n1) { n1 = m; }
}
return m3 < 0 || n1 == 0 || n1 * n2 < m1 * m2 ?
m1 * m2 * m3 : n1 * n2 * m3;
https://www.online-python.com/FufUN9vAEp
You can use:
import java.util.Arrays;
public class LargestMultiple {
private static void storeValues(
int new_value,
int[] values
)
{
int i = -1;
for (;i + 1 < values.length && new_value > values[i+1]; ++i){}
if (i >= 0)
{
for (int j = 0; j < i; ++j)
{
values[j] = values[j+1];
}
values[i] = new_value;
}
}
public static int findTriplet(
int[] a
)
{
if (a.length == 0)
{
throw new IllegalArgumentException("Not enough values");
}
if (a.length <= 3)
{
int value = a[0];
for (int i = 1; i < a.length; ++i)
{
value *= a[i];
}
return value;
}
int[] maximums = {0, 0, 0};
int[] minimums = {0, 0};
int[] negatives = {Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE};
int num_positive = 0;
for (int i = 0; i < a.length; i++)
{
if (a[i] < 0)
{
storeValues(-a[i], minimums);
storeValues(a[i], negatives);
}
else
{
storeValues(a[i], maximums);
num_positive++;
}
}
if (num_positive > 0)
{
return Math.max(
minimums[0] * minimums[1],
maximums[0] * maximums[1]
) * maximums[2];
}
else
{
return negatives[0] * negatives[1] * negatives[2];
}
}
public static void test(final int[] values)
{
System.out.println(
Arrays.toString(values)
+ " -> "
+ findTriplet(values)
);
}
public static void main(final String[] args)
{
test(new int[]{1});
test(new int[]{1, 2});
test(new int[]{1, 2, 3});
test(new int[]{1, 2, 3, 4});
test(new int[]{1, 2, -1, -2});
test(new int[]{1, 2, -1});
test(new int[]{1, 2, 3, -1});
test(new int[]{1, 2, 3, -1, -4});
test(new int[]{-1, -2, -3, -4});
}
}
Which outputs:
[1] -> 1
[1, 2] -> 2
[1, 2, 3] -> 6
[1, 2, 3, 4] -> 24
[1, 2, -1, -2] -> 4
[1, 2, -1] -> -2
[1, 2, 3, -1] -> 6
[1, 2, 3, -1, -4] -> 12
[-1, -2, -3, -4] -> -6
Note: Although storeValues is O(N) on the size of the array, it is always called from findTriplet with fixed-sized arrays then, from within that function, it will have a constant O(1) execution time.
The result is always the product of the 3 highest numbers or of the highest and the 2 lowest numbers. So the 2 lowest and the 3 highest numbers have to be found. An O(n) solution is therefore possible since this can be done in one loop pass.
public static int findTriplet(int[] a) {
if(a.length < 3) throw new IllegalArgumentException("The array must have a length of at least 3!");
int[] n = {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE };
for(int i : a) {
// find two lowest
if(i < n[0]) { n[1] = n[0]; n[0] = i; }
else if (i < n[1]) n[1] = i;
// find three highest
if(i > n[4]) { n[2] = n[3]; n[3] = n[4]; n[4] = i; }
else if(i > n[3]) { n[2] = n[3]; n[3] = i; }
else if(i > n[2]) n[2] = i;
}
int case1 = n[0] * n[1];
int case2 = n[2] * n[3];
return n[4] * (case1 > case2 ? case1 : case2);
}
Given an array of integers and a sum, the task is to print all subsets of given array with sum equal to given sum.
Example:
Input : arr[] = {1, 2, 3, 4, 5}
sum = 10
Output : [4 3 2 1]
[5 3 2]
[5 4 1]
Input : arr[] = {-1, 2, 3, 4, 5}
sum = 10
Output : [5 3 2]
[5 4 2 -1]
I have done that using dynamic programming in pseudo polynomial time. This is an extension of subset sum problem, which only takes care of deciding whether such a subset exist or not. My solution below works for both positive and negative numbers for the subset sum problem. However, it is not able to print the subsets correctly if the array contains negative numbers.The program is-
import java.util.ArrayList;
// sum problem
class GFG {
static boolean subset[][];
// Returns true if there is a subset of
// set[] with sun equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum) {
// The value of subset[i][j] will be
// true if there is a subset of
// set[0..j-1] with sum equal to i
subset = new boolean[n + 1][sum + 1];
// Fill the subset table in botton
// up manner
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
if (j == 0) {
subset[i][j] = true;
} else if (i <= 0 && sum >= 1)
subset[i][j] = false;
else if (set[i - 1] > j)
subset[i][j] = subset[i - 1][j];
else {
if (set[i - 1] >= 0)
subset[i][j] = subset[i - 1][j] || subset[i - 1][j - set[i - 1]];
else
subset[i][j] = subset[i - 1][j] || subset[i - 1][j + set[i - 1]];
}
}
}
// uncomment this code to print table
// for (int i = 0; i <= sum; i++)
// {
// for (int j = 0; j <= n; j++)
// System.out.println (subset[i][j]);
// }
return subset[n][sum];
}
/* Driver program to test above function */
public static void main(String args[]) {
int set[] = {1, 2, 3, 4, 5};
int sum = 10;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
System.out.println("Done");
ArrayList<Integer> list = new ArrayList<>();
printSubsets(set, n, sum, list);
System.out.println("Finished");
}
static void display(ArrayList<Integer> v) {
System.out.println(v);
}
private static void printSubsets(int[] set, int i, int sum, ArrayList<Integer> list) {
if (i == 0 && sum != 0 && subset[0][sum]) {
list.add(set[i]);
display(list);
list.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0) {
display(list);
list.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (subset[i - 1][sum]) {
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(list);
printSubsets(set, i - 1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= set[i - 1] && subset[i - 1][sum - set[i - 1]]) {
list.add(set[i - 1]);
printSubsets(set, i - 1, sum - set[i - 1], list);
}
}
}
How this code can be modified to work for negative numbers as well?
Your solutions assumes that all values are positive, so the dynamic programing array subset is filled with the values of j that are positive, but you need to take into account negative sums now.
What you need to do is to change the loop limits of j to fill the dynamic programing array to
for (int j = negative_sum; j <= positive_sum; j++)
Where negative_sum is the sum of all the negative values and positive_sum is the sum of all the positive ones.
For more details read the wikipedia page for the Subset Sum Problem here where this step is explained.
Since you have to print ( or generate ) all possible subset of given set (containing both positive and negative integers) which have summation equal to sum, what you can do is :
try to represent each position of set as binary representation of 0 and 1, where 1 indicates that element at that position is taken and 0 indicates that element at that position is not taken into account.
Find the summation of all positions where there is 1. If the summation of these values is exactly equals to the given sum, then print that subset.
So, overall time complexity is O(2 ^ n), where n is length of given set.
You may look at following implementation.
import java.util.Arrays;
public class PerfectSum {
public static void printSubsets(int[] set, int n, int sum) {
int totalSubSets = (1 << n);
for (int i = 1; i < totalSubSets; ++i) { // loop over all possible subsets
int curSum = 0;
for (int j = n - 1; j >= 0; --j) {
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
curSum +=set[j];
}
}
if (curSum == sum) { // valid subset found, then print it
for (int j = n - 1; j >= 0; --j) { // looping in reverse order to print set in decreasing order
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
System.out.print(set[j] + " ");
}
}
System.out.println("");
}
}
}
public static void main(String[] args) {
int set[] = {-1, 2, 3, 4, 5};
Arrays.sort(set); // To print in non increasing order
int sum = 10;
int n = set.length;
printSubsets(set, n, sum);
}
}
You can subtract the minimum negative number of the array to the entire set, making the numbers in the array positive. Then apply dynamic programming.
If you have the binary number 10110 how can I get it to return 5? e.g a number that tells how many bits are used? There are some likewise examples listed below:
101 should return 3
000000011 should return 2
11100 should return 5
101010101 should return 9
How can this be obtained the easiest way in Java? I have come up with the following method but can i be done faster:
public static int getBitLength(int value)
{
if (value == 0)
{
return 0;
}
int l = 1;
if (value >>> 16 > 0) { value >>= 16; l += 16; }
if (value >>> 8 > 0) { value >>= 8; l += 8; }
if (value >>> 4 > 0) { value >>= 4; l += 4; }
if (value >>> 2 > 0) { value >>= 2; l += 2; }
if (value >>> 1 > 0) { value >>= 1; l += 1; }
return l;
}
Easiest?
32 - Integer.numberOfLeadingZeros(value)
If you are looking for algorithms, the implementors of the Java API agree with your divide-and-conquer bitshifting approach:
public static int numberOfLeadingZeros(int i) {
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
}
Edit: As a reminder to those who trust in the accuracy of floating point calculations, run the following test harness:
public static void main(String[] args) {
for (int i = 0; i < 64; i++) {
long x = 1L << i;
check(x);
check(x-1);
}
}
static void check(long x) {
int correct = 64 - Long.numberOfLeadingZeros(x);
int floated = (int) (1 + Math.floor(Math.log(x) / Math.log(2)));
if (floated != correct) {
System.out.println(Long.toString(x, 16) + " " + correct + " " + floated);
}
}
The first detected deviation is:
ffffffffffff 48 49
Unfortunately there is no Integer.bitLength() method that would give you the answer directly.
An analogous method exists for BigInteger, so you could use that one:
BigInteger.valueOf(value).bitLength()
Constructing the BigInteger object will make it somewhat less efficient, but that will only matter if you do it many millions of times.
You want to compute the base 2 logarithm of the number - specifically: 1 + floor(log2(value))
Java has a Math.log method which uses base e, so you can do:
1 + Math.floor(Math.log(value) / Math.log(2))
Be careful what you ask for. One very fast technique is to do a table lookup:
int bittable [] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... };
int numbits (int v)
{
return bittable [v];
}
where bittable contains an entry for every int. Of course that has complications for negative values. A more practical way would be to count the bits in bitfields of the number
int bittable [16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
int numbits (int v)
{
int s = 0;
while (v != 0)
{
s += bittable [v & 15];
v >>= 4;
}
return s;
}
You really just want to find the position of the highest bit that is a 1. See this page, under the heading "Finding integer log base 2 of an integer (aka the position of the highest bit set)".
From here, a way to do it with just bitwise-and and addition:
int GetHighestBitPosition(int value) {
if (value == 0) return 0;
int position = 1;
if ((value & 0xFFFF0000) == 0) position += 16;
if ((value & 0xFF00FF00) == 0) position += 8;
if ((value & 0xF0F0F0F0) == 0) position += 4;
if ((value & 0xCCCCCCCC) == 0) position += 2;
if ((value & 0xAAAAAAAA) == 0) position += 1;
return position;
}
Integer.toBinaryString(value).length()
I think the rounded-up log_2 of that number will give you what you need.
Something like:
return (int)(Math.log(value) / Math.log(2)) + 1;
int CountBits(uint value)
{
for (byte i = 32; i > 0; i--)
{
var b = (uint)1 << (i - 1);
if ((value & b) == b)
return i;
}
return 0;
}
If you are looking for the fastest (and without a table, which is certainly faster), this is probably the one:
public static int bitLength(int i) {
int len = 0;
while (i != 0) {
len += (i & 1);
i >>>= 1;
}
return len;
}
Another solution is to use the length() of a BitSet which according to the API
Returns the "logical size" ... the index of
the highest set bit ... plus one.
To use the BitSet you need to create an array. So it is not as simple as starting with a pure int. But you get it out of the JDK box - tested and supported. It would look like this:
public static int bitsCount(int i) {
return BitSet.valueOf(new long[] { i }).length();
}
Applied to the examples in the question:
bitsCount(0b101); // 3
bitsCount(0b000000011); // 2
bitsCount(0b11100); // 5
bitsCount(0b101010101); // 9
When asking for bits the BitSetseems to me to be the appropriate data structure.
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;
}