Finding nearest non-coprime number - java

Given an array, I need to find the indices of nearest non-coprime number (i.e. GCD(Ai, Aj) > 1 , for any Ai and Aj in the array, i != j ) Example, let the array be
[2 17 4 6 10]
The answer will be
[3 -1 4 3 4]
I've written this brute force code (which is O(n^2)) using Binary GCD method, which is not very efficient. I'm wondering if there's a faster way to do this. Particularly in O(NlogN)
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
/**
* Built using CHelper plug-in
* Actual solution is at the top
*
* #author Mayur Kulkarni
*/
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
BladeReader in = new BladeReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
GCDPuz solver = new GCDPuz();
solver.solve(1, in, out);
out.close();
}
static class GCDPuz {
public static int gcd(int p, int q) {
if (q == 0) return p;
if (p == 0) return q;
// p and q even
if ((p & 1) == 0 && (q & 1) == 0) return gcd(p >> 1, q >> 1) << 1;
// p is even, q is odd
else if ((p & 1) == 0) return gcd(p >> 1, q);
// p is odd, q is even
else if ((q & 1) == 0) return gcd(p, q >> 1);
// p and q odd, p >= q
else if (p >= q) return gcd((p - q) >> 1, q);
// p and q odd, p < q
else return gcd(p, (q - p) >> 1);
}
public int coprime(int p, int q) {
if (p % 2 == 0 && q % 2 == 0) {
return 2;
} else if (p == q + 1 || q == p + 1) {
return 1;
} else {
return gcd(p, q);
}
}
public void solve(int testNumber, BladeReader in, PrintWriter out) {
int size = in.nextInt();
int[] arr = in.readIntArray(size);
int[] ans = new int[size];
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 1) {
ans[i] = -1;
continue;
}
int left = i == 0 ? -1 : findLeft(arr, i);
int right = i == arr.length - 1 ? -1 : findRight(arr, i);
int leftDist = left == -1 ? -1 : i - left;
int rightDist = right == -1 ? -1 : right - i;
int anss = findNearestIndex(left, leftDist, right, rightDist);
ans[i] = anss == -1 ? -1 : anss + 1;
}
printa(ans, out);
}
private void printa(int[] ans, PrintWriter out) {
StringBuilder sb = new StringBuilder();
for (int an : ans) {
sb.append(an).append(" ");
}
out.println(sb.toString());
}
private int findRight(int[] arr, int i) {
if (arr[i] == -1) return -1;
for (int j = i + 1; j < arr.length; j++) {
if (coprime(arr[i], arr[j]) > 1) return j;
}
return -1;
}
private int findLeft(int[] arr, int i) {
if (arr[i] == -1) return -1;
for (int j = i - 1; j >= 0; j--) {
if (coprime(arr[i], arr[j]) > 1) return j;
}
return -1;
}
private int findNearestIndex(int one, int oneDist, int two, int twoDist) {
if (oneDist == -1 && twoDist == -1) return -1;
if (oneDist == -1) return two;
if (twoDist == -1) return one;
if (oneDist == twoDist) {
return Math.min(one, two);
}
return oneDist < twoDist ? one : two;
}
}
static class BladeReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public BladeReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public int[] readIntArray(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = nextInt();
}
return array;
}
}
}

If you know your max value for your numbers and can afford to keep a list of primes, then factoring them may be a better solution for the average/random case. Otherwise, worst case complexity, it's still O(N*N) - think "all of them are primes" for the worst case.
Approach:
factor them and store a Map<prime, multiplicity>[N] + int closestNeigh[]
take a factor and O(N) determine for each of them the closest that contain that factor (prefix/sufix sums will be involved)
eliminate that factor from all the factor maps
take the next factor. Adjust the closest neighbor index only if new one is closest.
This may bring some "relief" on the line of O(N*<num_distict_factors>), but again if <num_distict_factors> == N (all primes), then it is still O(N*N)

If you are willing to get into factorization, one could traverse the list, once from the left, factoring each number, hashing the index of each new prime (with the prime as the key), updating the index of each prime already seen, and, of course, noting the nearest seen prime. Since this traversal would miss the nearest on the right, conduct another traversal from the right to update any nearer shared prime, using the factor lists already saved.

Related

Java Large Number Operations Shortest Path to One

A week ago I was given a challenge from my professor to make a program that has three operations for large numbers, given as as strings. I could only pass five of the ten test cases and got an A anyway, but I still want to know what you guys would do for this problem, as far as programming techniques or an approach I didn't think of..
You are given a String representation of a number that is up to 309 digits long. You can preform three operations:
1) Add 1 to the number
2) Subtract 1
3) Divide by 2
the purpose of the program is to find the shortest path, or smallest amount of operations that can be performed on this number so that the result is 1.
ex: given "11"
1 -> 2 -> 3 -> 6 -> 12 -> 11
result: 5 steps
I had two approaches that didn't work 100%:
1: start from one or the number itself and recursively step through each possible answer until number is reached within a maximum number of steps (eg. 11, 20).
2: define all possible answers with the help of a 2-d boolean array with all possible permutaions, then step through the possible movesets one by one. this array works as a map conceptually.
Both of these approaches had limited success, wether i encountered a stackoverflow error or just ran out of memory with my large arrays. This forced me to limit the number of steps so the code could function somewhat successfully. What would be your approach?
EDIT 1:30pm
attempt 1(sorry, it has been edited severely, hence why it wasn't shown earlier...):
import java.math.BigInteger;
import java.util.Scanner;
public class Answer {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static BigInteger minNumOfJumps;
private static BigInteger big2 = BigInteger.valueOf(2);
/** smallest Number of jumps reached so far */
private static BigInteger smallestAmountOfJumps;
public static int answer(String string) {
// TODO Auto-generated method stub
BigInteger src = new BigInteger(string);
// BigInteger currentJump = BigInteger.ZERO; //used to initialize the
// nodes
// minNumOfJumps = src.divide(big2).add(BigInteger.ONE); //this must
// execute...
minNumOfJumps = new BigInteger("14"); // this must execute...
smallestAmountOfJumps = new BigInteger(minNumOfJumps.toString());
// System.out.println(minNumOfJumps);
Node n = new Node(src); // ...before this
return Integer.parseInt(getSmallestAmountOfJumps().toString());
// System.out.println(n.getSmallestAmountOfJumps().toString());
}
public static BigInteger getBig2() {
return big2;
}
public static void setBig2(BigInteger big2) {
Answer.big2 = big2;
}
public static BigInteger getMinNumOfJumps() {
return minNumOfJumps;
}
public static BigInteger getSmallestAmountOfJumps() {
return smallestAmountOfJumps;
}
public static void setSmallestAmountOfJumps(String smallestAmountOfJumps) {
Answer.smallestAmountOfJumps = new BigInteger(smallestAmountOfJumps);
}
}
/*
* I have never made a shortest path algorithm before, so i hope this is toyour
* satisfaction
*/
class Node {
/** number of nodes per creation */
private static final int NUMBER_OF_NODES_PER_NODE = 3;
/** if this number is exceeded, no more jumps are necessary. */ // SAVE THAT
// THINKING
// JUICE!
// private static BigInteger POSSIBLE_MINIMUM_NUMBER_OF_JUMPS;
private static boolean lastTransformWasRemoveOne;
private static boolean lastTransformWasAddOne;
// if one is the given value(src)
// private boolean isOneReached;
/** if the current path isn't valid */
// private boolean threadIsBroken;
// value passed during creation
private BigInteger src;
// current jump
private BigInteger currentJump;
// all possible transformations during next jump
// private Node[] path;
private Node(BigInteger src, BigInteger jump) {
currentJump = jump;
this.src = src;
// POSSIBLE_MINIMUM_NUMBER_OF_JUMPS = Answer.getMinNumOfJumps();
// this.path = new Node[NUMBER_OF_NODES_PER_NODE];
// 0 = remove | 1 = add | 2 = divide
for (int i = 0; i < NUMBER_OF_NODES_PER_NODE; i++) {
// System.out.println("i: " + i);
// System.out.println("src: " + src);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (src.compareTo(BigInteger.ONE) == 0) {
if (currentJump.subtract(Answer.getSmallestAmountOfJumps()).compareTo(BigInteger.ZERO) == -1) {
Answer.setSmallestAmountOfJumps(currentJump.toString());
// this below may break the code, but i think it fits with
// the logic
break;
}
} else if (i == 0) { // remove 1
// System.out.println(lastTransformWasAddOne);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (!lastTransformWasAddOne && currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) {
lastTransformWasRemoveOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
}
} else if (i == 1 && !lastTransformWasRemoveOne
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // add
// 1
lastTransformWasAddOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (src.mod(Answer.getBig2()) == BigInteger.ZERO
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // divide
// by
// 2
lastTransformWasRemoveOne = false;
lastTransformWasAddOne = false;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (currentJump.compareTo(Answer.getSmallestAmountOfJumps()) == 0)
break;
}
}
private BigInteger transform(int i) {
// TODO Auto-generated method stub
return (i == 0) ? src.subtract(BigInteger.ONE)
: (i == 1) ? src.add(BigInteger.ONE) : (i == 2) ? src.divide(Answer.getBig2()) : BigInteger.ZERO;
}
/**
* To be called once and only once.
*/
public Node(BigInteger src) {
this(src, BigInteger.ZERO);
}
}`
and this is another attempt:
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class AnswerLessProficient {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static boolean notFirstCall;
private static boolean pathIsSet;
private static boolean[][] boolArray;
private static final String ZERO = "0";
private static final BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE);
private static int maximumSteps;
private static int maximumPermutations;
private static ArrayList<byte[]> listOfPaths;
private static Set<byte[]> setOfPaths;
// private static final int maximumPermutations = halfMaximumPermutations *
// 2;
// private static byte[][] path;
private static BigInteger src;
private static int steps;
private static BigInteger tempSrc;
private static byte[] tempPath;
// private static boolean followThePathsWithAlternateRoutesWasCalledOnce;
public static int answer(String s) {
// listOfPaths = new ArrayList<>();
src = new BigInteger(s);
tempSrc = new BigInteger(s);
maximumSteps = 9;
steps = maximumSteps;
maximumPermutations = (int) Math.pow(2, maximumSteps);
if (!notFirstCall) {
tempPath = new byte[maximumSteps];
setOfPaths = new HashSet<>();
int mercyVar = (int) Math.pow(2, maximumSteps);
// path = new byte[maximumPermutations][maximumSteps];
// boolArray = new boolean[maximumPermutations][maximumSteps];
for (int i = 0; i < mercyVar; i++) {
listOfPaths = new ArrayList<>();
String bin = (Integer.toBinaryString(i));
while (bin.length() < maximumSteps)
bin = (ZERO + bin);
char[] chars = bin.toString().toCharArray();
byte[] tempPath = new byte[maximumSteps];
for (int j = 0; j < maximumSteps; j++) {
// if (!pathIsSet)
// path[j] = -1;
if (chars[j] == '0') {
tempPath[j] = 2;
// path[i][j] = 2;
// boolArray[i][j] = true;
} else {
tempPath[j] = -1;
// path[i][j] = -1;
}
}
//System.out.println(Arrays.toString(tempPath));
listOfPaths.add(tempPath);
setOfPaths.add(tempPath);
findAltRoute(listOfPaths.size() - 1, maximumSteps - 1);
}
/*
* for (int i = mercyVar, j = 0; i < maximumPermutations; i++, j++)
* { for (int k = 0; k < maximumSteps; k++) { if (path[j][k] == -1)
* { path[i][k] = 1; } else { path[i][k] = 2; } } }
*/
// for (byte[] bs : setOfPaths) {
// System.out.println(Arrays.toString(bs));
// }
/*
* for (int i = maximumSteps - 1, k = 0; i >= 0 &&
* tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) { if
* (tempSrc.compareTo(BigInteger.ONE) <= 0) if (k < steps) { steps =
* k; maximumSteps = steps; System.out.println(Arrays.toString(bs));
* break; } else break; if (bs[i] == 2 && tempSrc.mod(TWO) !=
* BigInteger.ZERO) break; tempSrc = transform(tempSrc, bs[i]); }
* tempSrc = src.add(BigInteger.ZERO);
*/
// }
// System.out.println(bin);
/*
* for (int j = 0; j < maximumSteps && i >= halfMaximumPermutations;
* j++) { // if (!pathIsSet) // path[j] = -1; if (chars[j + 1] ==
* '0') { path[i][j] = 2; // boolArray[i][j] = true; } else {
* path[i][j] = 1; } }
*/
// System.out.println(bin);
// System.out.println(Arrays.toString(path[i]));
// pathIsSet = true;
notFirstCall = true;
}
justFollowThePath();
// System.out.println(Arrays.toString(path[0]));
// System.out.println
// (Arrays.toString(path[(int) (maximumPermutations/2)-1]));
// System.out.println(Arrays.toString(path[maximumPermutations-1]));
/**
* 561-508-2204 george rubio debt forgiveness; 305-709-8255
*/
// for (int i = 0; i < maximumPermutations; i++) {
// followThePathsWithAlternateRoutes(path[i], maximumSteps - 1);
// }
// followThePathsWithAlternateRoutesWasCalledOnce = false;
/*
* for (int i = 0; i < maximumPermutations; i++) { for (int k = 0; k <
* maximumSteps; k++) {
*
* }
*
* for (int k = maximumSteps - 1; k > 0; k--) {
*
* } }
*/
// for (boolean[] bs : boolArray) {
// System.out.println(Arrays.toString(bs));
// }
// System.out.println(Arrays.toString(boolArray[maximumPermutations -
// 1]));
// System.out.println(Arrays.toString(path));
return steps;
}
private static void findAltRoute(int listIndex, int startingSearchIndex) {
if (listOfPaths.get(listIndex)[startingSearchIndex] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
// recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1,
// maximumSteps - 1);
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == 2) {
returnAltRoute(listIndex, i + 1, startingSearchIndex, (byte) 1, i);
findAltRoute(listIndex + 1, i);
return;
}
else if (i == 0) {
returnAltRoute(listIndex, i, startingSearchIndex, (byte) 1);
return;
}
}
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == -1 && listOfPaths.get(listIndex)[i + 1] == 2) {
if (i != 0) {
for (int k = i - 1; k >= 0; k--) {
if (listOfPaths.get(listIndex)[k] == 2 && listOfPaths.get(listIndex)[k + 1] == -1) {
// recurAlt(tempPath, i, k + 1, (byte) 1, k);
returnAltRoute(listIndex, k + 1, i, (byte) 1, k);
findAltRoute(listIndex, i);
}
// returnAltRoute(listIndex, 0, i, (byte)1);
// return;
}
} else {
returnAltRoute(listIndex, 0, i, (byte) 1);
return;
}
}
}
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
findAltRoute(listIndex, returnSearchInt);
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
}
private static void justFollowThePath() {
for (byte[] bs : setOfPaths) {
//System.out.println(tempSrc.toString());
for (int i = 0; i < maximumSteps && tempSrc.compareTo(BigInteger.ZERO) > 0; i++) {
if (tempSrc.compareTo(BigInteger.ONE) == 0)
if (i < steps) {
steps = i;
maximumSteps = steps;
//System.out.println(i);
// System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (bs[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, bs[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
}
private static void followThePathsWithAlternateRoutes(byte[] tempPath, int startingSearchIndex) {
if (tempPath[maximumSteps - 1] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1, maximumSteps - 1);
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (tempPath[i] == -1 && tempPath[i + 1] == 2) {
for (int k = i - 1; k > 0; k--) {
if (tempPath[k] == 2) {
recurAlt(tempPath, i, k + 1, (byte) 1, k);
}
}
}
}
System.out.println();
for (int i = maximumSteps - 1, k = 0; i >= 0 && tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) {
if (tempSrc.compareTo(BigInteger.ONE) <= 0)
if (k < steps) {
steps = k;
maximumSteps = steps;
System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (tempPath[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, tempPath[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
private static BigInteger transform(BigInteger temp, byte i) {
// TODO Auto-generated method stub
return (i == -1) ? tempSrc.subtract(BigInteger.ONE)
: (i == 1) ? tempSrc.add(BigInteger.ONE) : (i == 2) ? tempSrc.divide(TWO) : null;
}
private static void recurAlt(byte[] tempPath, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
// TODO Auto-generated method stub
byte[] temp = new byte[tempPath.length];
for (int i = 0; i < temp.length; i++) {
if (i >= tempStart && i <= tempEnd)
temp[i] = adjust;
else
temp[i] = tempPath[i];
}
followThePathsWithAlternateRoutes(temp, returnSearchInt);
}
}
there are other things i've tried, but you can see where i'm going. Any pointers?
If the number is even, divide by 2. If the number is 3 mod 4, add one unless the number is actually 3. Otherwise, subtract one. Repeat until you get to 1.
Here's a proof.
First note that if the number is even, it only makes sense to divide by 2. Because if you perform some number (say 2k) of +1 or -1, then divide by 2 that's the same as dividing by two and then adding or subtracting k 1's. So by dividing by two first, you save operations.
So the only question is whether to add or subtract 1 when the number is odd. You can prove by induction that the given strategy is correct.
An odd number n is either 4x+1 or 4x+3. Note that any sequence of operations (when we're dividing by 2 whenever possible) will at some point reach either x or x+1.
We'll consider each of these in turn, and count shortest paths to x and x+1. (Checking that I've correctly identified shortest paths is omitted).
In the first case (4x+1), by subtracting one first we can get to x in 3 steps (4x+1->4x->2x->x) and x+1 in 4 steps (4x+1->4x->2x->x->x+1). By adding one first, we can get to x in 4 steps (4x+1->4x+2->2x+1->2x->x) and x+1 in 4 steps (4x+1->4x+2->2x+1->2x+2->x+1). So we might as well always subtract 1 first.
In the second case (4x+3), by subtracting one first we can get to x in 4 steps (4x+3->4x+2->2x+1->2x->x), and x+1 in 4 steps (4x+3->4x+2->2x+1->2x+2->x+1). By adding one first, we can get to x+1 in 3 steps (4x+3->4x+4->2x+2->x+1), and x in 4 steps (4x+3->4x+4->2x+2->x+1->x). So we might as well always add 1 first in this case.
In the second case, if x=0 (that is n=4*0+3=3), then our reasoning doesn't quite work, since we won't, in fact, reach x. In this case we should subtract one and divide by 2 to reach 1.
The question is labelled java, but here's some pseudocode (actually Python) to produce optimal chains:
def chain(n):
while n:
print n,
if n % 2 == 0:
n //= 2
elif n % 4 == 3 and n != 3:
n += 1
else:
n -= 1
chain(11)
My first approach will be using BFS.
There are only 2 or 3 state transition ( I assume we can't divide odd number).
But this approach only fast enough for small number.
The second approach will be using A* with smallest number as heuristic function. For example when I start with "12", I can go to:
"11", "13", "6". I will choose "6" for the next state because it closer to "1".
However this approach still not fast enough.
My third approach will be generate the answer from "1" to "100" then looking for the pattern / formula.
Edit: remove wrong formula.

Faster GCD(n, m) in Java?

I'm working on something that's going to need to use the GCD algorithm quite a bit, and I'd like it to be as fast as possible. I've tried the normal method, binary method, and a memoisation method I thought would work better than it did. I copied the binary method from here, with minor tweaks.
I've been using a class called TestGCD for testing, here's the whole thing:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestGCD
{
private static class Pair<A>
{
private final A a_one;
private final A a_two;
public Pair(A a_one, A a_two)
{
this.a_one = a_one;
this.a_two = a_two;
}
#Override
public boolean equals(Object object)
{
if (this == object)
return true;
if (object == null)
return false;
if (!(object instanceof Pair))
return false;
final Pair other = (Pair) object;
if (a_one == null)
if (other.a_one != null)
return false;
if (a_two == null)
if (other.a_two != null)
return false;
if (a_one.equals(other.a_one))
if (a_two.equals(other.a_two))
return true;
if (a_one.equals(other.a_two))
if (a_two.equals(other.a_one))
return true;
return false;
}
public A getFirst()
{
return a_one;
}
public A getSecond()
{
return a_two;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
final int aOneHash = a_one == null ? 0 : a_one.hashCode();
final int aTwoHash = a_two == null ? 0 : a_two.hashCode();
int resultOneWay = prime * result + aOneHash;
resultOneWay += prime * result + aTwoHash;
int resultOtherWay = prime * result + aTwoHash;
resultOtherWay += prime * result + aOneHash;
result += resultOneWay + resultOtherWay;
return result;
}
#Override
public String toString()
{
return String.format("%s, %s", a_one, a_two);
}
}
private final static Map<Pair<Integer>, Integer> STORAGE = new HashMap<>();
private static void addNewPairs(List<Pair<Integer>> newPairs, int result)
{
for (final Pair<Integer> pair : newPairs)
STORAGE.put(pair, result);
}
private static int gcd(int x, int y)
{
if (x == 0)
return y;
if (y == 0)
return x;
int gcdX = Math.abs(x);
int gcdY = Math.abs(y);
if (gcdX == 1 || gcdY == 1)
return 1;
while (gcdX != gcdY)
if (gcdX > gcdY)
gcdX -= gcdY;
else
gcdY -= gcdX;
return gcdX;
}
private static int gcdBinary(int x, int y)
{
int shift;
/* GCD(0, y) == y; GCD(x, 0) == x, GCD(0, 0) == 0 */
if (x == 0)
return y;
if (y == 0)
return x;
int gcdX = Math.abs(x);
int gcdY = Math.abs(y);
if (gcdX == 1 || gcdY == 1)
return 1;
/* Let shift := lg K, where K is the greatest power of 2 dividing both x and y. */
for (shift = 0; ((gcdX | gcdY) & 1) == 0; ++shift)
{
gcdX >>= 1;
gcdY >>= 1;
}
while ((gcdX & 1) == 0)
gcdX >>= 1;
/* From here on, gcdX is always odd. */
do
{
/* Remove all factors of 2 in gcdY -- they are not common */
/* Note: gcdY is not zero, so while will terminate */
while ((gcdY & 1) == 0)
/* Loop X */
gcdY >>= 1;
/*
* Now gcdX and gcdY are both odd. Swap if necessary so gcdX <= gcdY,
* then set gcdY = gcdY - gcdX (which is even). For bignums, the
* swapping is just pointer movement, and the subtraction
* can be done in-place.
*/
if (gcdX > gcdY)
{
final int t = gcdY;
gcdY = gcdX;
gcdX = t;
} // Swap gcdX and gcdY.
gcdY = gcdY - gcdX; // Here gcdY >= gcdX.
}while (gcdY != 0);
/* Restore common factors of 2 */
return gcdX << shift;
}
private static int gcdMemoised(int x, int y)
{
if (x == 0)
return y;
if (y == 0)
return x;
int gcdX = Math.abs(x);
int gcdY = Math.abs(y);
if (gcdX == 1 || gcdY == 1)
return 1;
final List<Pair<Integer>> newPairs = new ArrayList<>();
while (gcdX != gcdY)
{
final Pair<Integer> pair = new Pair<>(gcdX, gcdY);
final Integer result = STORAGE.get(pair);
if (result != null)
{
addNewPairs(newPairs, result);
return result;
}
else
newPairs.add(pair);
if (gcdX > gcdY)
gcdX -= gcdY;
else
gcdY -= gcdX;
}
addNewPairs(newPairs, gcdX);
return gcdX;
}
So is there a way of making this algorithm faster or is the original version the fastest I'm going to get? No suggestions of using another language please, I'm looking for an algorithm improvement. Clearly my memoisation attempt was an utter failure, but maybe someone here can see a flaw/improve on it.
You can use Euclid's algorithm. It is very simple to implement and it is more efficient. Here is a code for it:
static int gcd(int a, int b) {
while (b != 0) {
int t = a;
a = b;
b = t % b;
}
return a;
}
The time complexity is O(log(A + B)), while the algorithms you are using are O(A + B). It scales better and is efficient for small a and b, too.
Here is what I came up with, on the same lines as #ILoveCoding
public static long gcd(long first, long second) {
long big = 0;
long small = 0;
if(first > second) {
big=first;
small=second;
}
else {
big=second;
small=first;
}
long temp = big % small;
while( (temp) > 1 ) {
big = small;
small = temp;
temp = big % small;
}
if( temp == 0 ) {
return small ;
}
else if( temp == 1) {
return 1;
}
else {
return -1; // will never occur. hack for compilation error.
}
}
Edit: Test cases !
System.out.println( gcd(10L, 5L));
System.out.println( gcd(11L, 7L));
System.out.println( gcd(15L, 21L));
System.out.println( gcd(-2L, -5L));
System.out.println( gcd(-2L, 2L));
Euclidean Algorithm used by author of the question (subtraction-based version) and accepted answer (mod-based) both seems to be quite not as efficient as Binary GCD Algorithm, so here it's code in java (taken from wikipidea)
static long gcd(long u, long v) {
int shift;
if (u == 0) return v;
if (v == 0) return u;
for (shift = 0; ((u | v) & 1) == 0; ++shift) {
u >>= 1;
v >>= 1;
}
while ((u & 1) == 0) {
u >>= 1;
}
do {
while ((v & 1) == 0) {
v >>= 1;
}
if (u > v) {
long t = v;
v = u;
u = t;
}
v = v - u;
} while (v != 0);
return u << shift;
}
However, Binary algorithm is not the fastest gcd algorithm. More here.
Use Euclidean Algorithm for GCD
The algorithm is based on below facts.
If we subtract smaller number from larger (we reduce larger number),
GCD doesn’t change. So if we keep subtracting repeatedly the larger
of two, we end up with GCD.
Now instead of subtraction, if we divide smaller number, the
algorithm stops when we find remainder 0.
Code:
import java.util.*;
import java.lang.*;
class GFG
{
public static int gcd(int a, int b)
{
if (a == 0)
return b;
return gcd(b%a, a);
}
public static void main(String[] args)
{
int a = 10, b = 15, g;
g = gcd(a, b);
System.out.println("GCD(" + a + " , " + b+ ") = " + g);
}
}
Time Complexity: O(Log min(a, b))

java codility Frog-River-One

I have been trying to solve a Java exercise on a Codility web page.
Below is the link to the mentioned exercise and my solution.
https://codility.com/demo/results/demoH5GMV3-PV8
Can anyone tell what can I correct in my code in order to improve the score?
Just in case here is the task description:
A small frog wants to get to the other side of a river. The frog is currently located at position 0, and wants to get to position X. Leaves fall from a tree onto the surface of the river.
You are given a non-empty zero-indexed array A consisting of N integers representing the falling leaves. A[K] represents the position where one leaf falls at time K, measured in minutes.
The goal is to find the earliest time when the frog can jump to the other side of the river. The frog can cross only when leaves appear at every position across the river from 1 to X.
For example, you are given integer X = 5 and array A such that:
A[0] = 1
A[1] = 3
A[2] = 1
A[3] = 4
A[4] = 2
A[5] = 3
A[6] = 5
A[7] = 4
In minute 6, a leaf falls into position 5. This is the earliest time when leaves appear in every position across the river.
Write a function:
class Solution { public int solution(int X, int[] A); }
that, given a non-empty zero-indexed array A consisting of N integers and integer X, returns the earliest time when the frog can jump to the other side of the river.
If the frog is never able to jump to the other side of the river, the function should return −1.
For example, given X = 5 and array A such that:
A[0] = 1
A[1] = 3
A[2] = 1
A[3] = 4
A[4] = 2
A[5] = 3
A[6] = 5
A[7] = 4
the function should return 6, as explained above. Assume that:
N and X are integers within the range [1..100,000];
each element of array A is an integer within the range [1..X].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(X), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
And here is my solution:
import java.util.ArrayList;
import java.util.List;
class Solution {
public int solution(int X, int[] A) {
int list[] = A;
int sum = 0;
int searchedValue = X;
List<Integer> arrayList = new ArrayList<Integer>();
for (int iii = 0; iii < list.length; iii++) {
if (list[iii] <= searchedValue && !arrayList.contains(list[iii])) {
sum += list[iii];
arrayList.add(list[iii]);
}
if (list[iii] == searchedValue) {
if (sum == searchedValue * (searchedValue + 1) / 2) {
return iii;
}
}
}
return -1;
}
}
You are using arrayList.contains inside a loop, which will traverse the whole list unnecessarily.
Here is my solution (I wrote it some time ago, but I believe it scores 100/100):
public int frog(int X, int[] A) {
int steps = X;
boolean[] bitmap = new boolean[steps+1];
for(int i = 0; i < A.length; i++){
if(!bitmap[A[i]]){
bitmap[A[i]] = true;
steps--;
if(steps == 0) return i;
}
}
return -1;
}
Here is my solution. It got me 100/100:
public int solution(int X, int[] A)
{
int[] B = A.Distinct().ToArray();
return (B.Length != X) ? -1 : Array.IndexOf<int>(A, B[B.Length - 1]);
}
100/100
public static int solution (int X, int[] A){
int[]counter = new int[X+1];
int ans = -1;
int x = 0;
for (int i=0; i<A.length; i++){
if (counter[A[i]] == 0){
counter[A[i]] = A[i];
x += 1;
if (x == X){
return i;
}
}
}
return ans;
}
A Java solution using Sets (Collections Framework) Got a 100%
import java.util.Set;
import java.util.TreeSet;
public class Froggy {
public static int solution(int X, int[] A){
int steps=-1;
Set<Integer> values = new TreeSet<Integer>();
for(int i=0; i<A.length;i++){
if(A[i]<=X){
values.add(A[i]);
}
if(values.size()==X){
steps=i;
break;
}
}
return steps;
}
Better approach would be to use Set, because it only adds unique values to the list. Just add values to the Set and decrement X every time a new value is added, (Set#add() returns true if value is added, false otherwise);
have a look,
public static int solution(int X, int[] A) {
Set<Integer> values = new HashSet<Integer>();
for (int i = 0; i < A.length; i++) {
if (values.add(A[i])) X--;
if (X == 0) return i;
}
return -1;
}
do not forget to import,
import java.util.HashSet;
import java.util.Set;
Here's my solution, scored 100/100:
import java.util.HashSet;
class Solution {
public int solution(int X, int[] A) {
HashSet<Integer> hset = new HashSet<Integer>();
for (int i = 0 ; i < A.length; i++) {
if (A[i] <= X)
hset.add(A[i]);
if (hset.size() == X)
return i;
}
return -1;
}
}
Simple solution 100%
public int solution(final int X, final int[] A) {
Set<Integer> emptyPosition = new HashSet<Integer>();
for (int i = 1; i <= X; i++) {
emptyPosition.add(i);
}
// Once all the numbers are covered for position, that would be the
// moment when the frog will jump
for (int i = 0; i < A.length; i++) {
emptyPosition.remove(A[i]);
if (emptyPosition.size() == 0) {
return i;
}
}
return -1;
}
Here's my solution.
It isn't perfect, but it's good enough to score 100/100.
(I think that it shouldn't have passed a test with a big A and small X)
Anyway, it fills a new counter array with each leaf that falls
counter has the size of X because I don't care for leafs that fall farther than X, therefore the try-catch block.
AFTER X leafs fell (because it's the minimum amount of leafs) I begin checking whether I have a complete way - I'm checking that every int in count is greater than 0.
If so, I return i, else I break and try again.
public static int solution(int X, int[] A){
int[] count = new int[X];
for (int i = 0; i < A.length; i++){
try{
count[A[i]-1]++;
} catch (ArrayIndexOutOfBoundsException e){ }
if (i >= X - 1){
for (int j = 0; j< count.length; j++){
if (count[j] == 0){
break;
}
if (j == count.length - 1){
return i;
}
}
}
}
return -1;
}
Here's my solution with 100 / 100.
public int solution(int X, int[] A) {
int len = A.length;
if (X > len) {
return -1;
}
int[] isFilled = new int[X];
int jumped = 0;
Arrays.fill(isFilled, 0);
for (int i = 0; i < len; i++) {
int x = A[i];
if (x <= X) {
if (isFilled[x - 1] == 0) {
isFilled[x - 1] = 1;
jumped += 1;
if (jumped == X) {
return i;
}
}
}
}
return -1;
}
Here's what I have in C#. It can probably still be refactored.
We throw away numbers greater than X, which is where we want to stop, and then we add numbers to an array if they haven't already been added.
When the count of the list has reached the expected number, X, then return the result. 100%
var tempArray = new int[X+1];
var totalNumbers = 0;
for (int i = 0; i < A.Length; i++)
{
if (A[i] > X || tempArray.ElementAt(A[i]) != 0)
continue;
tempArray[A[i]] = A[i];
totalNumbers++;
if (totalNumbers == X)
return i;
}
return -1;
below is my solution. I basically created a set which allows uniques only and then go through the array and add every element to set and keep a counter to get the sum of the set and then using the sum formula of consecutive numbers then I got 100% . Note : if you add up the set using java 8 stream api the solution is becoming quadratic and you get %56 .
public static int solution2(int X, int[] A) {
long sum = X * (X + 1) / 2;
Set<Integer> set = new HashSet<Integer>();
int setSum = 0;
for (int i = 0; i < A.length; i++) {
if (set.add(A[i]))
setSum += A[i];
if (setSum == sum) {
return i;
}
}
return -1;
}
My JavaScript solution that got 100 across the board. Since the numbers are assumed to be in the range of the river width, simply storing booleans in a temporary array that can be checked against duplicates will do. Then, once you have amassed as many numbers as the quantity X, you know you have all the leaves necessary to cross.
function solution(X, A) {
covered = 0;
tempArray = [];
for (let i = 0; i < A.length; i++) {
if (!tempArray[A[i]]) {
tempArray[A[i]] = true;
covered++
if(covered === X) return i;
}
}
return -1;
}
Here is my answer in Python:
def solution(X, A):
# write your code in Python 3.6
values = set()
for i in range (len(A)):
if A[i]<=X :
values.add(A[i])
if len(values)==X:
return i
return -1
Just tried this problem as well and here is my solution. Basically, I just declared an array whose size is equal to position X. Then, I declared a counter to monitor if the necessary leaves have fallen at the particular spots. The loop exits when these leaves have been met and if not, returns -1 as instructed.
class Solution {
public int solution(int X, int[] A) {
int size = A.length;
int[] check = new int[X];
int cmp = 0;
int time = -1;
for (int x = 0; x < size; x++) {
int temp = A[x];
if (temp <= X) {
if (check[temp-1] > 0) {
continue;
}
check[temp - 1]++;
cmp++;
}
if ( cmp == X) {
time = x;
break;
}
}
return time;
}
}
It got a 100/100 on the evaluation but I'm not too sure of its performance. I am still a beginner when it comes to programming so if anybody can critique the code, I would be grateful.
Maybe it is not perfect but its straightforward. Just made a counter Array to track the needed "leaves" and verified on each iteration if the path was complete. Got me 100/100 and O(N).
public static int frogRiver(int X, int[] A)
{
int leaves = A.Length;
int[] counter = new int[X + 1];
int stepsAvailForTravel = 0;
for(int i = 0; i < leaves; i++)
{
//we won't get to that leaf anyway so we shouldnt count it,
if (A[i] > X)
{
continue;
}
else
{
//first hit!, keep a count of the available leaves to jump
if (counter[A[i]] == 0)
stepsAvailForTravel++;
counter[A[i]]++;
}
//We did it!!
if (stepsAvailForTravel == X)
{
return i;
}
}
return -1;
}
This is my solution. I think it's very simple. It gets 100/100 on codibility.
set.contains() let me eliminate duplicate position from table.
The result of first loop get us expected sum. In the second loop we get sum of input values.
class Solution {
public int solution(int X, int[] A) {
Set<Integer> set = new HashSet<Integer>();
int sum1 = 0, sum2 = 0;
for (int i = 0; i <= X; i++){
sum1 += i;
}
for (int i = 0; i < A.length; i++){
if (set.contains(A[i])) continue;
set.add(A[i]);
sum2 += A[i];
if (sum1 == sum2) return i;
}
return -1;
}
}
Your algorithm is perfect except below code
Your code returns value only if list[iii] matches with searchedValue.
The algorithm must be corrected in such a way that, it returns the value if sum == n * ( n + 1) / 2.
import java.util.ArrayList;
import java.util.List;
class Solution {
public int solution(int X, int[] A) {
int list[] = A;
int sum = 0;
int searchedValue = X;
int sumV = searchedValue * (searchedValue + 1) / 2;
List<Integer> arrayList = new ArrayList<Integer>();
for (int iii = 0; iii < list.length; iii++) {
if (list[iii] <= searchedValue && !arrayList.contains(list[iii])) {
sum += list[iii];
if (sum == sumV) {
return iii;
}
arrayList.add(list[iii]);
}
}
return -1;
}
}
I think you need to check the performance as well. I just ensured the output only
This solution I've posted today gave 100% on codility, but respectivly #rafalio 's answer it requires K times less memory
public class Solution {
private static final int ARRAY_SIZE_LOWER = 1;
private static final int ARRAY_SIZE_UPPER = 100000;
private static final int NUMBER_LOWER = ARRAY_SIZE_LOWER;
private static final int NUMBER_UPPER = ARRAY_SIZE_UPPER;
public static class Set {
final long[] buckets;
public Set(int size) {
this.buckets = new long[(size % 64 == 0 ? (size/64) : (size/64) + 1)];
}
/**
* number should be greater than zero
* #param number
*/
public void put(int number) {
buckets[getBucketindex(number)] |= getFlag(number);
}
public boolean contains(int number) {
long flag = getFlag(number);
// check if flag is stored
return (buckets[getBucketindex(number)] & flag) == flag;
}
private int getBucketindex(int number) {
if (number <= 64) {
return 0;
} else if (number <= 128) {
return 1;
} else if (number <= 192) {
return 2;
} else if (number <= 256) {
return 3;
} else if (number <= 320) {
return 4;
} else if (number <= 384) {
return 5;
} else
return (number % 64 == 0 ? (number/64) : (number/64) + 1) - 1;
}
private long getFlag(int number) {
if (number <= 64) {
return 1L << number;
} else
return 1L << (number % 64);
}
}
public static final int solution(final int X, final int[] A) {
if (A.length < ARRAY_SIZE_LOWER || A.length > ARRAY_SIZE_UPPER) {
throw new RuntimeException("Array size out of bounds");
}
Set set = new Set(X);
int ai;
int counter = X;
final int NUMBER_REAL_UPPER = min(NUMBER_UPPER, X);
for (int i = 0 ; i < A.length; i++) {
if ((ai = A[i]) < NUMBER_LOWER || ai > NUMBER_REAL_UPPER) {
throw new RuntimeException("Number out of bounds");
} else if (ai <= X && !set.contains(ai)) {
counter--;
if (counter == 0) {
return i;
}
set.put(ai);
}
}
return -1;
}
private static int min(int x, int y) {
return (x < y ? x : y);
}
}
This is my solution it got me 100/100 and O(N).
public int solution(int X, int[] A) {
Map<Integer, Integer> leaves = new HashMap<>();
for (int i = A.length - 1; i >= 0 ; i--)
{
leaves.put(A[i] - 1, i);
}
return leaves.size() != X ? -1 : Collections.max(leaves.values());
}
This is my solution
public func FrogRiverOne(_ X : Int, _ A : inout [Int]) -> Int {
var B = [Int](repeating: 0, count: X+1)
for i in 0..<A.count {
if B[A[i]] == 0 {
B[A[i]] = i+1
}
}
var time = 0
for i in 1...X {
if( B[i] == 0 ) {
return -1
} else {
time = max(time, B[i])
}
}
return time-1
}
A = [1,2,1,4,2,3,5,4]
print("FrogRiverOne: ", FrogRiverOne(5, &A))
Actually I re-wrote this exercise without seeing my last answer and came up with another solution 100/100 and O(N).
public int solution(int X, int[] A) {
Set<Integer> leaves = new HashSet<>();
for(int i=0; i < A.length; i++) {
leaves.add(A[i]);
if (leaves.contains(X) && leaves.size() == X) return i;
}
return -1;
}
I like this one better because it is even simpler.
This one works good on codality 100% out of 100%. It's very similar to the marker array above but uses a map:
public int solution(int X, int[] A) {
int index = -1;
Map<Integer, Integer> map = new HashMap();
for (int i = 0; i < A.length; i++) {
if (!map.containsKey(A[i])) {
map.put(A[i], A[i]);
X--;
if (X == 0) {index = i;break;}
}
}
return index;
}
%100 with js
function solution(X, A) {
let leafSet = new Set();
for (let i = 0; i < A.length; i += 1) {
if(A[i] <= 0)
continue;
if (A[i] <= X )
leafSet.add(A[i]);
if (leafSet.size == X)
return i;
}
return -1;
}
With JavaScript following solution got 100/100.
Detected time complexity: O(N)
function solution(X, A) {
let leaves = new Set();
for (let i = 0; i < A.length; i++) {
if (A[i] <= X) {
leaves.add(A[i])
if (leaves.size == X) {
return i;
}
}
}
return -1;
}
100% Solution using Javascript.
function solution(X, A) {
if (A.length === 0) return -1
if (A.length < X) return -1
let steps = X
const leaves = {}
for (let i = 0; i < A.length; i++) {
if (!leaves[A[i]]) {
leaves[A[i]] = true
steps--
}
if (steps === 0) {
return i
}
}
return -1
}
C# Solution with 100% score:
using System;
using System.Collections.Generic;
class Solution {
public int solution(int X, int[] A) {
// go through the array
// fill a hashset, until the size of hashset is X
var set = new HashSet<int>();
int i = 0;
foreach (var a in A)
{
if (a <= X)
{
set.Add(a);
}
if (set.Count == X)
{
return i;
}
i++;
}
return -1;
}
}
https://app.codility.com/demo/results/trainingXE7QFJ-TZ7/
I have a very simple solution (100% / 100%) using HashSet. Lots of people check unnecessarily whether the Value is less than or equal to X. This task cannot be otherwise.
public static int solution(int X, int[] A) {
Set<Integer> availableFields = new HashSet<>();
for (int i = 0; i < A.length; i++) {
availableFields.add(A[i]);
if (availableFields.size() == X){
return i;
}
}
return -1;
}
public static int solutions(int X, int[] A) {
Set<Integer> values = new HashSet<Integer>();
for (int i = 0; i < A.length; i++) {
if (values.add(A[i])) {
X--;
}
if (X == 0) {
return i;
}
}
return -1;
}
This is my solution. It uses 3 loops but is constant time and gets 100/100 on codibility.
class FrogLeap
{
internal int solution(int X, int[] A)
{
int result = -1;
long max = -1;
var B = new int[X + 1];
//initialize all entries in B array with -1
for (int i = 0; i <= X; i++)
{
B[i] = -1;
}
//Go through A and update B with the location where that value appeared
for (int i = 0; i < A.Length; i++)
{
if( B[A[i]] ==-1)//only update if still -1
B[A[i]] = i;
}
//start from 1 because 0 is not valid
for (int i = 1; i <= X; i++)
{
if (B[i] == -1)
return -1;
//The maxValue here is the earliest time we can jump over
if (max < B[i])
max = B[i];
}
result = (int)max;
return result;
}
}
Short and sweet C++ code. Gets perfect 100%... Drum roll ...
#include <set>
int solution(int X, vector<int> &A) {
set<int> final;
for(unsigned int i =0; i< A.size(); i++){
final.insert(A[i]);
if(final.size() == X) return i;
}
return -1;
}

Fastest algorithm to check if a number is pandigital?

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

Refactor for loops into function

I've got this piece of java code:
int maxDigit = 4;
for(int a = 0; a <= maxDigit; a++)
{
for(int b = 0; b <= maxDigit; b++)
{
if(b != a){
for(int c = 0; c <= maxDigit; c++)
{
if(c != a && c != b)
{
for(int d = 0; d <= maxDigit; d++)
{
if(d != a && d != b && d != c)
{
for(int e = 0; e <= maxDigit; e++)
{
if(e != a && e != b && e != c && e != d)
{
String temp = a + "" + b + "" + c + "" + d + "" + e;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
}
}
}
}
}
}
}
}
}
How can you transform this piece of code into a function?
The purpose is to generate permutations of the digits 0 to 9 and here in the code above it is from 0 to 4. And it seems easy to put it in a function but i couldn't find it immediately.
This is a variant of the classic problem of getting all permutations of a string.
The induction your professor wants you to make is that this problem lends itself well to a solution that uses recursion.
The basic algorithm for the permutations of string s is as follows:
Select the first item in s.
Get all permutations of the other items in s (except the item selected).
Prepend selected item to each permutation from step 2.
Repeat for the next character of s.
Here's an efficient solution using the Functional Java library.
Import these...
import fj.F;
import fj.P2;
import fj.P1;
import fj.data.Stream;
import static fj.data.Stream.nil;
import static fj.data.Stream.cons;
import static fj.data.Stream.range;
import static fj.data.Enumerator.charEnumerator;
import static fj.data.Show.streamShow;
import static fj.data.Show.charShow;
import static fj.P2.map2_;
A recursive function to find permutations:
public Stream<Stream<Character>> permutations(final Stream<Character> s) {
return selections(s).bind(
new F<P2<Character, Stream<Character>>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>>()
f(final P2<Character, Stream<Character>> ys) {
return permutations(ys._2()).bind(cons(ys._1()));
}
});
}
A recursive function to select each element in turn:
public Stream<P2<Character, Stream<Character>>>
selections(final Stream<Character> s) {
if (xs.isEmpty())
return nil();
else {
final char x = xs.head();
final Stream<Character> xs = s.tail()._1();
return cons(P.p(x, xs),
new P1<Stream<P2<Character, Stream<Character>>>>() {
public Stream<P2<Character, Stream<Character>>> _1() {
return selections(xs).map(map2_().f(cons(x))));
}
});
}
}
and then, to get all permutations of characters '0' through '9':
Show<Stream<Character>> s = streamShow(charShow);
for (Stream<Character> ps : permutations(range(charEnumerator, '0', '9'))) {
System.out.println(s.showS(ps));
}
EDIT: This is actually a great use case for comonads. Using the latest trunk head of Functional Java, you can do this with the Zipper comonad, like so:
public static Stream<Stream<Character>> perms(Stream<Character> s) {
Stream<Stream<Character>> r = single(Stream.<Character>nil());
for (final Zipper<Character> z : fromStream(s))
r = join(z.cobind(
new F<Zipper<Character>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>> f(final Zipper<Character> zp) {
return perms(zp.lefts().reverse().append(zp.rights())).map(compose(
Stream.<Character>cons().f(zp.focus()),
P.<Stream<Character>>p1()));
}
}).toStream());
return r;
}
Fill the holes:
int[] indexes = { 0, 0, 0, 0, 0 };
addPermutations(maxDigit, indexes, 0, permutations);
void addPermutations(int max, int[] indexes, int currentIndex, List<Integer> permutations) {
if (currentIndex == indexes.length) {
// terminal case
String temp = ...;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
} else {
// recursive case
for (int i = 0; i <= max; i++) {
if (... != i) {
indexes[currentIndex] = i;
addPermutations(max, indexes, currentIndex+1, permutations);
}
}
}
}
No code, but an algorithm should be as follows.
Suppose you want all permutations of 5 digits from 0 to 7. To do that:
Calculate j = decimal value of base-7 value of 100000 (1 + 5 zeroes)
Loop for i = 0; i < j; ++i, converting each i to base-7 system, optionally prepending with zeroes.
You could use an N-ary tree, with 4 branches at each point, recursively navigate the tree and step over branches where that node's digit had already been seen?

Categories

Resources