I know this question has been asked many times, but I'm looking for a very fast algorithm to generate all permutations of Strings of length 8. I am trying to generate a String of length 8, where each character in the String can be any of the characters 0-9 or a-z (36 total options). Currently, this is the code I have to do it:
for(idx[2] = 0; idx[2] < ch1.length; idx[2]++)
for(idx[3] = 0; idx[3] < ch1.length; idx[3]++)
for(idx[4] = 0; idx[4] < ch1.length; idx[4]++)
for(idx[5] = 0; idx[5] < ch1.length; idx[5]++)
for(idx[6] = 0; idx[6] < ch1.length; idx[6]++)
for(idx[7] = 0; idx[7] < ch1.length; idx[7]++)
for(idx[8] = 0; idx[8] < ch1.length; idx[8]++)
for(idx[9] = 0; idx[9] < ch1.length; idx[9]++)
String name = String.format("%c%c%c%c%c%c%c%c%c%c",ch1[idx[0]],ch2[idx[1]],ch3[idx[2]],ch4[idx[3]],ch5[idx[4]],ch6[idx[5]],ch7[idx[6]],ch8[idx[7]],ch9[idx[8]],ch10[idx[9]]);
As you can see, this code is not pretty by any means. Also, this code can generate 280 thousand Strings per second. I'm looking for an algorithm to do it even faster than that.
I've tried a recursive approach, but that seems to run slower than this approach does. Suggestions?
Should be faster (generates way above million outputs per second), and at least it's definitely more pleasant to read:
final long count = 36L * 36L * 36L * 36L * 36L * 36L * 36L * 36L;
for (long i = 0; i < count; ++i) {
String name = StringUtils.leftPad(Long.toString(i, 36), 8, '0');
}
This exploits the fact that your problem:
generate a String of length 8, where each character in the String can be any of the characters 0-9 or a-z (36 total options)
Can be reformulated to:
Print all numbers from 0 until 36^8 in base-36 system.
Few notes:
output is sorted by definition, nice!
I'm using StringUtils.leftPad() for simplicity, see also: How can I pad an integers with zeros on the left?
what you are looking for is not really a permutation
by exploiting the fact that you generate all subsequent numbers you can easily improve this algorithm even further:
final int MAX = 36;
final long count = 1L * MAX * MAX * MAX * MAX * MAX * MAX * MAX * MAX * MAX * MAX;
final char[] alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
final int[] digits = new int[8];
final char[] output = "00000000".toCharArray();
for (long i = 0; i < count; ++i) {
final String name = String.valueOf(output);
// "increment"
for (int d = 7; d >= 0; --d) {
digits[d] = (digits[d] + 1) % MAX;
output[d] = alphabet[digits[d]];
if (digits[d] > 0) {
break;
}
}
}
Program above, on my computer, generate more than 30 million strings per second. And there's still much room for improvement.
This code may look a little prettier - or at least more complex ;)
boolean incrementIndex( int[] idx, final int maxValue ) {
int i = 0;
int currIndexValue;
do {
currIndexValue = idx[i];
currIndexValue++;
if ( currIndexValue > maxValue ) {
currIndexValue = 0;
}
idx[i] = currIndexValue;
i++;
} while ( currIndexValue == 0 && i < idx.length );
return i < idx.length;
}
do {
// create String from idx[0]...idx[8]
} while ( incrementIndex(idx, 35) );
Related
I'm new to coding and have been set a challenge of creating an method that prints out a multiplication array.
My code is as follows...
public class TimesTableArray
{
public static void main(String[] args)
{
int size = 12;
int number = 3;
}
private static int [] getTimesTable(int size, int number)
{
int[] timesTable = new int[size];
for (int i = 0; i < size; i++)
{
timesTable[i] = number * (i +1);
}
return timesTable;
}
}
I get the following output...
3
6
9
12
15
18
21
24
27
30
33
0
I need the 12th item to read 36, not 0. I know it's to do with the index reads from 0 to 11, but I don't know how to amend my code to make this so.
Please could someone guide me on how to do this?
You have a classic "off by one" error.
If you start at 1, then you INCLUDE the size, and have to subtract one to get the Index:
for (int i = 1; i <= size; i++)
{
timesTable[i - 1] = number * i;
}
If you start at 0, then you EXCLUDE the size, and have to add one when you multiply:
for (int i = 0; i < size; i++)
{
timesTable[i] = number * (i + 1);
}
You're going to have people swear up and down that one is correct and the other is wrong. This is down to preference. Do what "makes sense" to you.
In the population loop, you are iterating from 1 rather than 0 but you do not offset the terminal condition. I would rewrite you loop to follow the standard pattern rather than trying to bake in the offset. So...
for (int index = 0 ; index < size ; ++index) { ... }
This will allow the index to line up naturally in the assignment. Apply the offset in the calcuation.
timesTable[index] = number * (index + 1);
So you get...
private static int[] getTimesTable(int size, int number) {
int[] timesTable = new int[size];
for (int i = 0; i < size; i++) {
timesTable[i] = number * (i+1);
}
return timesTable;
}
You are having an off-by-one error. Since you want to have an array of 12 answers, starting with 1, your loop range has to be from 1 to 12 inclusive. Therefore:
private static int [] getTimesTable(int size, int number)
{
int[] timesTable = new int[size];
for (int i = 1; i <= (size); i++)
{
timesTable[i-1] = number * i;
}
return timesTable;
}
The reason why your last index was zero, is because numeric array indexes are initialized to zero after instantiation (new int[size]).
So I'm trying to implement this pseudo-code for the radix sort and don't understand how to create a 2D ArrayList that this code is implying must be created. I've looked at other posts on creating a 2D ArrayList but don't understand how to properly implement it in this situation. Any help would be much appreciated.
RadixSort(array, arraySize) {
buckets = create array of 10 buckets
// Find the max length, in number of digits
maxDigits = RadixGetMaxLength(array, arraySize)
// Start with the least significant digit
pow10 = 1
for (digitIndex = 0; digitIndex < maxDigits; digitIndex++) {
for (i = 0; i < arraySize; i++) {
bucketIndex = abs(array[i] / pow10) % 10
Append array[i] to buckets[bucketIndex]
}
arrayIndex = 0
for (i = 0; i < 10; i++) {
for (j = 0; j < buckets[i].size(); j++)
array[arrayIndex++] = buckets[i][j]
}
pow10 = 10 * pow10
Clear all buckets
}
}
int buckets[][] = new int[10][arraySize]; // create array of 10 buckets
I am able to break up paragraphs of text into substrings based upon nth given character limit. The conflict I have is that my algorithm is doing exactly this, and is breaking up words. This is where I am stuck. If the character limit occurs in the middle of a word, how can I back track to a space so that all my substrings have entire words?
This is the algorithm I am using
int arrayLength = 0;
arrayLength = (int) Math.ceil(((mText.length() / (double) charLimit)));
String[] result = new String[arrayLength];
int j = 0;
int lastIndex = result.length - 1;
for (int i = 0; i < lastIndex; i++) {
result[i] = mText.substring(j, j + charLimit);
j += charLimit;
}
result[lastIndex] = mText.substring(j);
I am setting the charLimit variable with any nth, integer value. And mText is string with a paragraph of text. Any suggestions on how I can improve this? Thank you in advance.
I am receiving good responses, just so you know what I did to figure out of I landed on a space or not, I used this while loop. I just do not know how to correct from this point.
while (!strTemp.substring(strTemp.length() - 1).equalsIgnoreCase(" ")) {
// somehow refine string before added to array
}
Not sure if I understood correctly what you wanted but an answer to my interpretation:
You could find the last space before your character limit with lastIndexOf and then check if you are close enough to your limit (for text without whitespace) i.e.:
int arrayLength = 0;
arrayLength = (int) Math.ceil(((mText.length() / (double) charLimit)));
String[] result = new String[arrayLength];
int j = 0;
int tolerance = 10;
int splitpoint;
int lastIndex = result.length - 1;
for (int i = 0; i < lastIndex; i++) {
splitpoint = mText.lastIndexOf(' ' ,j+charLimit);
splitpoint = splitpoint > j+charLimit-tolerance ? splitpoint:j+charLimit;
result[i] = mText.substring(j, splitpoint).trim();
j = splitpoint;
}
result[lastIndex] = mText.substring(j).trim();
this will search for the last space before charLimit (example value) and either split the string there if it is less then tolerance away or split at charLimit if it isn't.
Only problem with this solution is that the last Stringtoken can be longer than charLimit so you might need to adjust arrayLength and loop while (mText - j > charLimit)
Edit
running sample code:
public static void main(String[] args) {
String mText = "I am able to break up paragraphs of text into substrings based upon nth given character limit. The conflict I have is that my algorithm is doing exactly this, and is breaking up words. This is where I am stuck. If the character limit occurs in the middle of a word, how can I back track to a space so that all my substrings have entire words?";
int charLimit = 40;
int arrayLength = 0;
arrayLength = (int) Math.ceil(((mText.length() / (double) charLimit)));
String[] result = new String[arrayLength];
int j = 0;
int tolerance = 10;
int splitpoint;
int lastIndex = result.length - 1;
for (int i = 0; i < lastIndex; i++) {
splitpoint = mText.lastIndexOf(' ' ,j+charLimit);
splitpoint = splitpoint > j+charLimit-tolerance ? splitpoint:j+charLimit;
result[i] = mText.substring(j, splitpoint);
j = splitpoint;
}
result[lastIndex] = mText.substring(j);
for (int i = 0; i<arrayLength; i++) {
System.out.println(result[i]);
}
}
Output:
I am able to break up paragraphs of text
into substrings based upon nth given
character limit. The conflict I have is
that my algorithm is doing exactly
this, and is breaking up words. This is
where I am stuck. If the character
limit occurs in the middle of a word,
how can I back track to a space so that
all my substrings have entire words?
Additional Edit: added trim() as per suggestion by curiosu. It removes whitespace surroundig the string tokens.
00101=5 digits, disregard two Zeros and calculate
0+(5-2-1)^2 = 4
4+(5-3-1)^2 = 5
5+(5-4-1)^2 = 5
final answer Is it Correct?
char[] charArray = binary.toCharArray();
double answer = 0;
for (double index = 0; index < charArray.length; index++)
{
if (charArray[(int)index] == '1')
{
answer = answer + Math.pow(2.0, (charArray.length - index - 1));
}
}
Use Integer.parseInt , that converts your String to int using base two:
int decimalValue = Integer.parseInt(c, 2);
Refer this:
http://docs.oracle.com/javase/6/docs/api/java/lang/Integer.html#parseInt%28java.lang.String,%20int%29
Your expected results are being calculated as if the binary string is read from right to left; however, your code is reading the binary string from left to right.
You can also try this:
char[] charArray = binary.toCharArray();
double answer = 0;
for (double index = charArray.length - 1; index >= 0; index--)
{
if (charArray[(int)index] == '1')
{
answer = answer + Math.pow(2.0, index);
}
}
Don't reinvent the Wheel. Use following simple code.
int dec=Integer.valueOf(binStr, 10);//Here 10 is base.
I am trying to create a bit vector backed by an int[].
So I have the following code:
public class BitVector {
int[] vector = new int[1 << 16];
public void setBit(int nextInt) {
nextInt = nextInt & 0xFFFF;
int pos = nextInt / 32;
int offset = nextInt % 32;
vector[pos] |= (1 << offset);
}
public int findClearedBit() {
for(int i = 0; i < vector.length; i++){
for(int j = 0; j < 8; j++){
if((vector[i] & (1 << j)) == 0)
return i * 32 + j;
}
}
return -1;
}
}
I know that perhaps I should have used byte[] instead etc but I was wondering why this way it does not work.
The idea is that I pass in int from a stream and keep the lower 16 bits and mark the corresponding bit as set. So when I iterate over the vector I will find the number (indicate by the lower 16 bits) missing.
But I get wrong result. So I believe my handing is wrong.
Any ideas?
Update:
I have a stream of 32-bit integers. As I read them in I try to mark a number missing by using the lower 16-bits and setting the bitvector (code posted).
I also try to find the upper 16 bits missing reading the stream a second time.
So while the missing number is: 231719592 = (1101110011111100001010101000) = (3535-49832)
When I read the stream I don't get 49832 as the missing lower bits but 65536
Update2:
public int findMissingInt(File f)throws Exception{
Scanner sc = new Scanner(f);
int SIZE = 1 << 16;
int[] occurences = new int[SIZE];
while(sc.hasNext()){
occurences[getIdx(sc.nextInt())]++;
}
int missingUpper = -1;
for(int i = 0; i < occurences.length; i++){
if(occurences[i] < SIZE){
System.out.println("Found upper bits:"+i);
missingUpper = i;
break;
}
}
if(missingUpper == -1){
return -1;
}
//Arrays.fill(occurences, 0); //I reused this. Bellow changed after answer of Peter de Rivaz
BitVector v = new BitVector(new int[1 << (16-5)]);
sc = new Scanner(f);
while(sc.hasNext()){
v.setBit(sc.nextInt());
}
int missingLower = v.findClearedBit();
System.out.println("Lower bits:"+missingLower);
return createNumber(missingUpper, missingLower);
}
private int createNumber(int missingUpper, int missingLower) {
int result = missingUpper;
result = result << 16;
return result | missingLower;
}
public int getIdx(int nextInt) {
return (nextInt >>> 16);
}
I get:
Missing number=231719592
Found upper bits:3535 //CORRECT
Lower bits:-1 //WRONG
Actual missing number=-1 //WRONG
I think there are two problems:
Your array has 65536 entries, but you store 32 bits in each entry, so you only need 65536/32 entries in it.
You store 32 bits in each int, but only check j from 0 to 7 when finding gaps
The first bug means that your program reports 65536 as a missing 16bit number.
The second bug means that your program does not spot the missing number.
i.e. change
int[] vector = new int[1 << 16];
to
int[] vector = new int[1 << (16-5)];
and change
for(int j = 0; j < 8; j++)
to
for(int j = 0; j < 32; j++)
EDIT
Judging from the comments, the question is actually how to find a missing number with limited RAM. The answer to this question can be found here on stackoverflow.
There is an additional bug in the higher level code.
During the second pass that populates the bitset, you should only include numbers that have the matching upper bits.
i.e. change
v.setBit(sc.nextInt());
to something like
int nx = sc.nextInt();
if (getIdx(nx)==missingUpper)
v.setBit(nx);