Permutation of string limited by another string - java

I'm having a bit of trouble, mainly because I do not have much experience with recursive methods and a non-recursive method for my problem seems incredibly complex. However, I might just be looking at this the wrong way.
What I'm trying to accomplish is this:
Given one string, I want to overlap them and display all potential combinations. It's probably easiest if I explain my problem and solution with binary representations.
Given 0000 and 1111,
I want my method to return:
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
This seems incredibly trivial, but I just can't seem to figure out the most efficient way of doing this. I was thinking either recursion or maybe a binary tree. Either way, I'm having trouble setting it up.
Any ideas would be greatly appreciated.
Thank you!

Poor, but passable iterative approach.
import java.util.BitSet;
public class p {
static StringBuilder sb;
// Add one and return true on overflow
static boolean inc( BitSet s, int maxlen ) {
int i = 0;
for( ; i < maxlen; ++i ) {
if( s.get( i )) { s.clear( i ); }
else { break; }
}
if( i == maxlen )
return true;
s.set( i );
return false;
}
static String form( String x, String y, BitSet mask ) {
sb.setLength( 0 );
for( int i = 0; i < x.length(); ++i )
sb.append( (mask.get( x.length() - i - 1) ? y : x).charAt( i ));
return sb.toString();
}
public static void perms( String x, String y ) {
assert( x.length() == y.length() );
BitSet bits = new BitSet( x.length() );
do {
System.out.println( form( x, y, bits ));
} while( ! inc( bits, x.length() ));
}
public static void main( String[] args ) {
sb = new StringBuilder( args[0].length() );
perms( args[0], args[1] );
}
}

Your binary explanation actually gave me a very good idea for doing this. You can simply use a for loop and increment the variable until it is 2 ^ str.Length * 2 - 1. In each iteration, one permutation is the characters from the first string where the corresponding bit in the variable is 0, or from the second string where it is 1. Pseudo-code:
for i = 0 to 2 ^ string1.length * 2 - 1
s = ""
for j = 0 to string1.length - 1
if (i >> j) & 1 == 1 then
s = string1[string1.length - j] + s
else
s = string2[string2.length - j] + s
end if
end for
end for

You want this:
/*************************************************************************
* Compilation: javac Permutations.java
* Execution: java Permutations N
*
* Enumerates all permutations on N elements.
* Two different approaches are included.
*
* % java Permutations 3
* abc
* acb
* bac
* bca
* cab
* cba
*
*************************************************************************/
public class Permutations {
// print N! permutation of the characters of the string s (in order)
public static void perm1(String s) { perm1("", s); }
private static void perm1(String prefix, String s) {
int N = s.length();
if (N == 0) System.out.println(prefix);
else {
for (int i = 0; i < N; i++)
perm1(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
}
}
// print N! permutation of the elements of array a (not in order)
public static void perm2(String s) {
int N = s.length();
char[] a = new char[N];
for (int i = 0; i < N; i++)
a[i] = s.charAt(i);
perm2(a, N);
}
private static void perm2(char[] a, int n) {
if (n == 1) {
System.out.println(a);
return;
}
for (int i = 0; i < n; i++) {
swap(a, i, n-1);
perm2(a, n-1);
swap(a, i, n-1);
}
}
// swap the characters at indices i and j
private static void swap(char[] a, int i, int j) {
char c;
c = a[i]; a[i] = a[j]; a[j] = c;
}
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String elements = alphabet.substring(0, N);
perm1(elements);
System.out.println();
perm2(elements);
}
}

Just for laughs, a very inefficient recursive solution:
import java.util.ArrayList;
public class pp {
static ArrayList<String> append(
String x, String y, ArrayList<String> ss ) {
if( x.length() == 0 )
return ss;
ArrayList<String> r = new ArrayList<String>( ss.size() * 2);
for( int i = 0; i < ss.size(); ++i ) {
r.add( ss.get( i ) + x.charAt( 0 ));
r.add( ss.get( i ) + y.charAt( 0 ));
}
return append( x.substring(1), y.substring(1), r );
}
public static void main( String[] args ) {
assert args[0].length() == args[1].length();
ArrayList<String> ss = new ArrayList<String>( 1 );
ss.add( "" );
ArrayList<String> r = append( args[0], args[1], ss );
for( int i = 0; i < r.size(); ++i )
System.out.println( r.get( i ));
}
}

Related

Computing All Valid IP Addresses From Raw IP String

I'm now solving leetcode problem 93. Restore IP Addresses.
Here's the url link: https://leetcode.com/problems/restore-ip-addresses/
The description looks like this:
Given a string s containing only digits. Return all possible valid IP addresses that can be obtained from s. You can return them in any order.
A valid IP address consists of exactly four integers, each integer is between 0 and 255, separated by single points and cannot have leading zeros. For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses and "0.011.255.245", "192.168.1.312" and "192.168#1.1" are invalid IP addresses.
However, as I was trying to solve my problem via backtracking, I couldn't figure out the reason that I'm always returning an empty ArrayList. I double checked my base case and my recursion and still couldn't find the bug. Any help would be greatly appreciated, thank you!
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
if(s.length() == 0){
return res;
}
int[] path = new int[4];
snapshotIP(res,s,0,path,0);
return res;
}
public void snapshotIP(List<String> res, String s, int index, int[] path, int segment){
if(segment == 4 && index == s.length()){
res.add(path[0]+"."+path[1]+"."+path[2]+"."+path[3]);
return;
}
else if(segment == 4 || index == s.length()){
return;
}
for(int len = 1; len <= 3 && index + len <= s.length(); len++){
String snap = s.substring(index,index+len);
int val = Integer.parseInt(snap);
if(val > 225 || len >= 2 && s.charAt(index) == '0'){
break;
}
path[segment] = val;
snapshotIP(res,s,index+len,path,segment+1);
path[segment] = -1; //undo the choice
}
}
You have written a pretty advanced code. It's working for all the cases where IP address segment is lower than 225, but the first test case has 255s in there.
The fix is trivial, just replace "val > 225" to "val > 255".
It should be like this:
if(val > 255 || len >= 2 && s.charAt(index) == '0')
P.S.
I would do this differently, I would add dots into every possible place and validate every received combination.
Your code looks pretty good, not bad at all, not sure where your bug is though.
Here is an alternative solution, not so pretty though, it would pass just fine:
public final class Solution {
public static final List<String> restoreIpAddresses(
final String ip
) {
List<String> res = new ArrayList<>();
int length = ip.length();
for (int i = 1; i < 4 && i < length - 2; i++)
for (int j = i + 1; j < i + 4 && j < length - 1; j++)
for (int k = j + 1; k < j + 4 && k < length; k++) {
final String part1 = ip.substring(0, i);
final String part2 = ip.substring(i, j);
final String part3 = ip.substring(j, k);
final String part4 = ip.substring(k, length);
if (isValid(part1) && isValid(part2) && isValid(part3) && isValid(part4)) {
res.add(part1 + "." + part2 + "." + part3 + "." + part4);
}
}
return res;
}
private static final boolean isValid(
final String s
) {
if (s.length() > 3 || s.length() == 0 || (s.charAt(0) == '0' && s.length() > 1) || Integer.parseInt(s) > 255) {
return false;
}
return true;
}
}
Something a bit suspicious in your code is that the backtracking helper function is void, maybe you've to define a variable to make it work, still unsure.
Similarly in C++, if you'd be interested:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
#include <string>
#define LIMIT 256
using ValueType = std::uint_fast16_t;
static const struct Solution {
static const std::vector<std::string> restoreIpAddresses(
const std::string s
) {
const ValueType len = std::size(s);
std::vector<std::string> ips;
std::string ip;
ValueType a, b, c, d;
ValueType A, B, C, D;
for (a = 1; a < 4; ++a) {
for (b = 1; b < 4; ++b) {
for (c = 1; c < 4; ++c) {
for (d = 1; d < 4; ++d) {
if (a + b + c + d == len) {
A = std::stoi(s.substr(0, a));
B = std::stoi(s.substr(a, b));
C = std::stoi(s.substr(a + b, c));
D = std::stoi(s.substr(a + b + c, d));
if (A < LIMIT && B < LIMIT && C < LIMIT && D < LIMIT) {
ip = std::to_string(A) + "." +
std::to_string(B) + "." +
std::to_string(C) + "." +
std::to_string(D);
if (std::size(ip) == len + 3) {
ips.emplace_back(ip);
}
}
}
}
}
}
}
return ips;
}
};
Here is LeetCode's backtracking depth first search algorithm that is similar to yours, that might help you figure it out.
class Solution {
int n;
String s;
LinkedList<String> segments = new LinkedList<String>();
ArrayList<String> output = new ArrayList<String>();
public boolean valid(String segment) {
/*
Check if the current segment is valid :
1. less or equal to 255
2. the first character could be '0'
only if the segment is equal to '0'
*/
int m = segment.length();
if (m > 3)
return false;
return (segment.charAt(0) != '0') ? (Integer.valueOf(segment) <= 255) : (m == 1);
}
public void update_output(int curr_pos) {
/*
Append the current list of segments
to the list of solutions
*/
String segment = s.substring(curr_pos + 1, n);
if (valid(segment)) {
segments.add(segment);
output.add(String.join(".", segments));
segments.removeLast();
}
}
public void backtrack(int prev_pos, int dots) {
/*
prev_pos : the position of the previously placed dot
dots : number of dots to place
*/
// The current dot curr_pos could be placed
// in a range from prev_pos + 1 to prev_pos + 4.
// The dot couldn't be placed
// after the last character in the string.
int max_pos = Math.min(n - 1, prev_pos + 4);
for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
String segment = s.substring(prev_pos + 1, curr_pos + 1);
if (valid(segment)) {
segments.add(segment); // place dot
if (dots - 1 == 0) // if all 3 dots are placed
update_output(curr_pos); // add the solution to output
else
backtrack(curr_pos, dots - 1); // continue to place dots
segments.removeLast(); // remove the last placed dot
}
}
}
public List<String> restoreIpAddresses(String s) {
n = s.length();
this.s = s;
backtrack(-1, 3);
return output;
}
}
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.
internal static IEnumerable<string> FetchPossibleIPs(string input, int currentSection = 1)
{
List<string> possibleIPs = new List<string>();
if (input.Length > 0)
{
// If section is 4 then no need
// to break further and simply verify.
if (currentSection == 4)
{
if (int.Parse(input) <= 255 && input[0].ToString() != "0")
{
possibleIPs.Add(input);
}
}
// Else if section is < 4 then break the string
// with substring of length of 1,2 or 3 to
// figure out possible combinations.
else
{
for (int i = 1; i <= 3; ++i)
{
var section = input.Substring(0, i);
if (int.Parse(section) <= 255 && section[0].ToString() != "0")
{
var otherSections = FetchPossibleIPs(input.Substring(i), currentSection + 1);
foreach (var item in otherSections)
{
possibleIPs.Add($"{section}.{item}");
}
}
}
}
}
return possibleIPs;
}
A sample solution in C# using recursion to solve it.
It uses recursion and backtracking to solve the problem.

Generating vampire numbers in free range

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

How to convert integers to base64 (0-9A-Za-z)

I have been trying to reduce the length of the way. I represent some integer ID's in my program. For Example
2
3
15
26
63
...
151564852
I would like them to be represented as such (0-9A-Za-z only)
2
3
F
Q
z
...
vDF25a //For example
The approach I thought of is to have 63 if statements which each of the mappings from 0-63 to 0-z respectively and for anything above 64 do a recursion on the value minus 63.
Needless to say, I think my approach is very flawed and impractical. What would be a more appropriate way of doing it?
Update:
Following fge's suggestion I've got the encoder to work correctly, however my decode function only works for up-to length 2 strings, in cases where the string is larger the sum becomes erroneous. For example for 3840 to 3845 this is the output
// Encoded
zw
x
zy
zz
100
// Decoded
3840
3841
3842
3843
124 //Invalid decoding
Here is my code for the decode function
public static int decode(String value)
{
String revStr = new StringBuilder(value).reverse().toString();
int sum = 0;
for (int i=1; i < revStr.length(); i++)
{
for (int j=0; j < ALPHABET.length; j++)
{
if (ALPHABET[j] == revStr.charAt(i))
{
sum += (ALPHABET.length * j) * i;
break;
}
}
}
for (int j=0; j < ALPHABET.length; j++)
{
if (ALPHABET[j] == revStr.charAt(0))
{
sum += j;
break;
}
}
return sum;
}
This is not base64; base64 encodes binary data.
Anyway, you don't need a s*load of if statements; use an array:
public final class AlphabetEncoder
{
private static final char[] ALPHABET = { '0', '1', '2', ...., 'z' };
private static final int ENCODE_LENGTH = ALPHABET.length;
public static String encode(int victim)
{
final List<Character> list = new ArrayList<>();
do {
list.add(ALPHABET[victim % ENCODE_LENGTH]);
victim /= ENCODE_LENGTH;
} while (victim > 0);
Collections.reverse(list);
return new String(list.toArray(new char[list.size()],
StandardCharsets.UTF_8);
}
public int decode(final String encoded)
{
int ret = 0;
char c;
for (int index = 0; index < encoded.length(); index++) {
c = encoded.charAt(index);
ret *= ENCODE_LENGTH;
ret += Arrays.binarySearch(ALPHABET, c);
}
return ret;
}
}
NOTE ABOUT THE DECODE FUNCTION: it is possible to use Arrays.binarySearch() here since the alphabet has the nice property of being naturally sorted (0 < 1 < 2 < ... < z). However, a test should probably be added that its return code not be negative!
Depending on the language you use, there should already be a module which converts a string from/to base64.
Check this other post: Base64 Encoding in Java
You can refer to already existing logic for converting from Decimal [0-9] to Hexadecimal conversion present in Integer class and extend the logic for your Base 64 converison. Refer
Integer.toHexString(int i)
This maybe the efficient implementation for conversion.
My thanks to the #fge answer.
Using it with some changes I've get it to support much larger integers with BigInteger, added support of negative integers and changed Arrays.binarySearch() with HashMap.
BTW, it should be called base62 encoding because [0-9A-Za-z] contains just 62 chars.
public class Base62{
private static final char[] ALPHABET = new char[ 62 ];
private static final Map<Character, Integer> ALPHABET_MAPPING = new HashMap<>();
private static final BigInteger ENCODE_LENGTH = BigInteger.valueOf( ALPHABET.length );
static{
int position = 0;
// numbers
for( int i = 48; i <= 57; i++ ){
ALPHABET[ position++ ] = (char)i;
}
// uppercase letters
for( int i = 65; i <= 90; i++ ){
ALPHABET[ position++ ] = (char)i;
}
// lowercase letters
for( int i = 97; i <= 122; i++ ){
ALPHABET[ position++ ] = (char)i;
}
for( int i = 0; i < ALPHABET.length; i++ ){
ALPHABET_MAPPING.put( ALPHABET[ i ], i );
}
}
public static String encode( final BigInteger in ){
final List<Character> list = new ArrayList<>();
boolean negative = in.signum() == -1;
BigInteger use;
if( negative ){
use = in.negate();
} else {
use = in;
}
do{
BigInteger[] divisionResultAndReminder = use.divideAndRemainder( ENCODE_LENGTH );
list.add( ALPHABET[ divisionResultAndReminder[ 1 ].intValue() ] );
use = divisionResultAndReminder[ 0 ];
} while( use.equals( BigInteger.ZERO ) == false );
Collections.reverse( list );
char[] res = new char[ list.size() ];
for( int i = 0; i < list.size(); i++ ){
res[ i ] = list.get( i );
}
return ( negative ? "-" : "" ) + new String( res );
}
public static BigInteger decode( final String encoded ){
BigInteger res = BigInteger.ZERO;
char c;
boolean negative;
String use;
if( '-' == encoded.charAt( 0 ) ){
negative = true;
use = encoded.substring( 1 );
} else {
negative = false;
use = encoded;
}
for( int index = 0; index < use.length(); index++ ){
c = use.charAt( index );
res = res.multiply( ENCODE_LENGTH );
res = res.add( BigInteger.valueOf( ALPHABET_MAPPING.get( c ) ) );
}
return negative ? res.negate() : res;
}
}

Permutate a String to upper and lower case

I have a string, "abc". How would a program look like (if possible, in Java) who permute the String?
For example:
abc
ABC
Abc
aBc
abC
ABc
abC
AbC
Something like this should do the trick:
void printPermutations(String text) {
char[] chars = text.toCharArray();
for (int i = 0, n = (int) Math.pow(2, chars.length); i < n; i++) {
char[] permutation = new char[chars.length];
for (int j =0; j < chars.length; j++) {
permutation[j] = (isBitSet(i, j)) ? Character.toUpperCase(chars[j]) : chars[j];
}
System.out.println(permutation);
}
}
boolean isBitSet(int n, int offset) {
return (n >> offset & 1) != 0;
}
As you probably already know, the number of possible different combinations is 2^n, where n equals the length of the input string.
Since n could theoretically be fairly large, there's a chance that 2^n will exceed the capacity of a primitive type such as an int. (The user may have to wait a few years for all of the combinations to finish printing, but that's their business.)
Instead, let's use a bit vector to hold all of the possible combinations. We'll set the number of bits equal to n and initialize them all to 1. For example, if the input string is "abcdefghij", the initial bit vector values will be {1111111111}.
For every combination, we simply have to loop through all of the characters in the input string and set each one to uppercase if its corresponding bit is a 1, else set it to lowercase. We then decrement the bit vector and repeat.
For example, the process would look like this for an input of "abc":
Bits:   Corresponding Combo:
111    ABC
110    ABc
101    AbC
100    Abc
011    aBC
010    aBc
001    abC
000    abc
By using a loop rather than a recursive function call, we also avoid the possibility of a stack overflow exception occurring on large input strings.
Here is the actual implementation:
import java.util.BitSet;
public void PrintCombinations(String input) {
char[] currentCombo = input.toCharArray();
// Create a bit vector the same length as the input, and set all of the bits to 1
BitSet bv = new BitSet(input.length());
bv.set(0, currentCombo.length);
// While the bit vector still has some bits set
while(!bv.isEmpty()) {
// Loop through the array of characters and set each one to uppercase or lowercase,
// depending on whether its corresponding bit is set
for(int i = 0; i < currentCombo.length; ++i) {
if(bv.get(i)) // If the bit is set
currentCombo[i] = Character.toUpperCase(currentCombo[i]);
else
currentCombo[i] = Character.toLowerCase(currentCombo[i]);
}
// Print the current combination
System.out.println(currentCombo);
// Decrement the bit vector
DecrementBitVector(bv, currentCombo.length);
}
// Now the bit vector contains all zeroes, which corresponds to all of the letters being lowercase.
// Simply print the input as lowercase for the final combination
System.out.println(input.toLowerCase());
}
public void DecrementBitVector(BitSet bv, int numberOfBits) {
int currentBit = numberOfBits - 1;
while(currentBit >= 0) {
bv.flip(currentBit);
// If the bit became a 0 when we flipped it, then we're done.
// Otherwise we have to continue flipping bits
if(!bv.get(currentBit))
break;
currentBit--;
}
}
String str = "Abc";
str = str.toLowerCase();
int numOfCombos = 1 << str.length();
for (int i = 0; i < numOfCombos; i++) {
char[] combinations = str.toCharArray();
for (int j = 0; j < str.length(); j++) {
if (((i >> j) & 1) == 1 ) {
combinations[j] = Character.toUpperCase(str.charAt(j));
}
}
System.out.println(new String(combinations));
}
You can also use backtracking to solve this problem:
public List<String> letterCasePermutation(String S) {
List<String> result = new ArrayList<>();
backtrack(0 , S, "", result);
return result;
}
private void backtrack(int start, String s, String temp, List<String> result) {
if(start >= s.length()) {
result.add(temp);
return;
}
char c = s.charAt(start);
if(!Character.isAlphabetic(c)) {
backtrack(start + 1, s, temp + c, result);
return;
}
if(Character.isUpperCase(c)) {
backtrack(start + 1, s, temp + c, result);
c = Character.toLowerCase(c);
backtrack(start + 1, s, temp + c, result);
}
else {
backtrack(start + 1, s, temp + c, result);
c = Character.toUpperCase(c);
backtrack(start + 1, s, temp + c, result);
}
}
Please find here the code snippet for the above :
public class StringPerm {
public static void main(String[] args) {
String str = "abc";
String[] f = permute(str);
for (int x = 0; x < f.length; x++) {
System.out.println(f[x]);
}
}
public static String[] permute(String str) {
String low = str.toLowerCase();
String up = str.toUpperCase();
char[] l = low.toCharArray();
char u[] = up.toCharArray();
String[] f = new String[10];
f[0] = low;
f[1] = up;
int k = 2;
char[] temp = new char[low.length()];
for (int i = 0; i < l.length; i++)
{
temp[i] = l[i];
for (int j = 0; j < u.length; j++)
{
if (i != j) {
temp[j] = u[j];
}
}
f[k] = new String(temp);
k++;
}
for (int i = 0; i < u.length; i++)
{
temp[i] = u[i];
for (int j = 0; j < l.length; j++)
{
if (i != j) {
temp[j] = l[j];
}
}
f[k] = new String(temp);
k++;
}
return f;
}
}
You can do something like
```
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String n=(args[0]);
HashSet<String>rs = new HashSet();
helper(rs,n,0,n.length()-1);
System.out.println(rs);
}
public static void helper(HashSet<String>rs,String res , int l, int n)
{
if(l>n)
return;
for(int i=l;i<=n;i++)
{
res=swap(res,i);
rs.add(res);
helper(rs,res,l+1,n);
res=swap(res,i);
}
}
public static String swap(String st,int i)
{
char c = st.charAt(i);
char ch[]=st.toCharArray();
if(Character.isUpperCase(c))
{
c=Character.toLowerCase(c);
}
else if(Character.isLowerCase(c))
{
c=Character.toUpperCase(c);
}
ch[i]=c;
return new String(ch);
}
}
```

Fastest algorithm to check if a number is pandigital?

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

Categories

Resources