Why does quot need to be repeatedly subtracted by 1? - java

This question is based off this thread Programming Riddle: How might you translate an Excel column name to a number?
Here is code from that question to translate a column number to an excel column name
public String getColName (int colNum) {
String res = "";
int quot = colNum;
int rem;
/*1. Subtract one from number.
*2. Save the mod 26 value.
*3. Divide the number by 26, save result.
*4. Convert the remainder to a letter.
*5. Repeat until the number is zero.
*6. Return that bitch...
*/
while(quot > 0)
{
quot = quot - 1;
rem = quot % 26;
quot = quot / 26;
//cast to a char and add to the beginning of the string
//add 97 to convert to the correct ascii number
res = (char)(rem+97) + res;
}
return res;
}
I tested this code thoroughly and it works but I have a question about what this line needs to be repeated for this to work
quot = quot - 1;
From my understanding the quot is needed to map the col number to distance away from 'a'. That means 1 should map to 0 distance from 'a', 2 to 1 distance away from 'a' and so on. But don't you need to subtract this one once to account for this? Not in a loop
I mean eventually,
quot = quot / 26;
will stop the loop.

Excel columns aren't a normal number system. It's not just base 26. The first two-digit column is "AA". In any normal number system, the first two digit number is composed of two different digits. Basically, in excel column numbering, there is no "zero" digit.
To account for this difference, 1 is subtracted at each iteration.

Related

Changing numbers depending on position

Hello I'm currently coding something for class. We are basically making a credit card checker to pull the numbers from a text file. The rules we have to follow for the check digit are the following.
Drop the last digit from the card number. The last digit is the check
digit.
Reverse the digits.
Multiply the digits in odd positions (1, 3, 5, etc.) by 2.
Subtract 9 from any result higher than 9.
Sum all the digits.
The check digit (the last number of the card) is the amount that you
would need to add to get a multiple of 10 (Modulo 10)
So I pulled the check digit away by setting a new variable and taking the card # /10. It's in a long so no decimals so this gets rid of the last digit. I then stored that digit as my check digit using %10 of the original number. I then used a loop to reverse the digits which can be seen as:
long lcards = Long.parseLong(cards);
long lastDigit = lcards % 10;
long newCard = lcards / 10;
long reverseCard = 0;
while (newCard != 0)
{
reverseCard = reverseCard * 10;
reverseCard = reverseCard + (newCard % 10);
newCard = newCard / 10;
}
I'm now stuck on the next step :/. How would I do this? Thanks!
Next step:
Multiply the digits in odd positions (1, 3, 5, etc.) by 2.
That requires you to iterate all digits in your input number. And there are two ways to do that:
More or less the same as your first attempt to get rid of the last digit - you can use modulo/division operations to "access" each digit in your number in a similar way as you did before!
Or, instead of working on one number, consider turning the whole number into an array of int values for example; like shown here. Now you can just iterate that array and make the necessary computations.
And in the end, just "merge" the array back into a single number. You could even do that upfront, to get rid of the last digit.
Hope that helps to get you going on the rest of the exercise!

How to Develop a Hash function for traffic license numbers?

Develop a hash function to generate an index value between 0-4999 inclusive for a given traffic license number. Your hash function should generate as few as possible collisions. Hash function should use the properties of license numbers. Hash method should take the license number as a single String and return an index value. We assume that the license numbers to be in the following format: City code is a number between 10 and 99 inclusive. Three letters are any letter combination from English alphabet with 26 chars. Two digits number is a number between 10 and 99 inclusive.
I wrote something about this question but, collisions are a lot (1800 for 5k)
static long printValue(String s) {
long result = 0;
for (int i = 0; i < s.length(); i++) {
result += Math.pow(27, MAX_LENGTH - i - 1) * (1 + s.charAt(i) - 'A');
}
result = result % 5009;
return (int) result;
}
public int hashF(String str) {
String a = str.substring(0, 2);
String b = str.substring(5, 7);
String middle = str.substring(2, 5);
int q = (int) printValue(middle);
String last = a + q + b;
int index = Integer.parseInt(last);
index = index % 5009;
return index;
}
Link for orjinal file of licence numbers.
These are some examples from file of traffic licence number. Collisions must be 300 (maximum).
65HNM25
93DTV23
94WPX23
31RKK46
15YXX90
31MDV74
45BOG99
65JRM50
77VXR55
39TKY41
80MJU73
63QYE57
38FCO80
45ORI16
17CHN73
70SXR63
87CVM74
27EEE85
32PFJ91
50PBA66
70TVK72
15YLS20
80MPM74
21ZRN20
36VVE84
58IDW24
77VDC89
19BVK93
28SUF63
Your problem is not your code, but mathematics. Even a (perfect for you, but not very useful) hash code that produces consecutive hashes that are then mod 5000, ie
10AAA10 -> 0
10AAA11 -> 1
... etc
99ZZZ99 -> 600 (90 * 26 * 26 * 26 * 90) % 5000
will statistically produce over 1800 collisions and is no better than the simplest implementation, which is to use String's hashCode:
int hash = Math.abs(number.hashCode() % 5000);
It's a silly exercise, as it has no real world use.
Your split of the license plate into 3 parts is fine. But converting the middle to a number, hashing it, then adding the two outside strings, converting that all to an integer, and then finally executing a modulo on that is ... awkward.
I would start off with converting the prefix (10-99) to an integer, and then subtracting 10 to get the range 0-89.
Then, for each letter, I'd multiply the result by 26, and add the index of the letter (0-25).
Third, I'd multiply the whole result by 90 (the range of the final part), convert the final 2 characters to an integer, subtract 10 to convert the 10-99 range to 0-89, and add to the result from earlier.
Finally, mod the result with 5000 to get to required 0-4999 range.
Pseudo code:
result = toInt(prefix) - 10
foreach letter in middle:
result = result * 26 + ( letter - 'A' )
result = result * 90 + ( toInt(suffix) - 10)
result = result % 5000

Generate a random number and add 0 before it to ensure fixed number of digits

so I am trying to generate a random number. I am going to append the day and month as integers before the random number. This I am able to do by using the following code.
Calendar calendar;
calendar=Calendar.getInstance();
int day= calendar.get(Calendar.DAY_OF_MONTH);
int month=calendar.get(Calendar.MONTH)+1; //it treats Jan as 0 hence i add 1
int num= Integer.valueOf(String.valueOf(month)+String.valueOf(day));
Now i need to generate a random number but add 0s before it. For example today is 21st September so numbers will look like
921 (num) + 22334 (random num) = 92122334
921 (num) + 2 (random num) = 92100002
Basically add 0s to the start ensuring number of digits remain the same. The use case of this is an easier way of generating unique order numbers that have an inbuilt time stamp as well. I dont expect to process more than 200 orders a day hence taking a 5 digit random number seems reasonable enough for probability of duplicates to be very small.
Two possible solutions.
Calendar calendar = GregorianCalendar.getInstance();
int num = 0;
num += (calendar.get(Calendar.MONTH) + 1) * 10_000_000;
num += calendar.get(Calendar.DAY_OF_MONTH) * 100_000;
num += your_random_number_lower_100000
second
Calendar calendar = GregorianCalendar.getInstance();
String randomDigits = String.format("%d%02d%05d",
calendar.get(Calendar.MONTH) + 1,
calendar.get(Calendar.DAY_OF_MONTH),
your_random_number_lower_100000
);
You can use String format:
String finalString = String.format("%d%05d", num, randomNum);
Here you can pass first parameter, Your calculation of day and month and second parameter Random number that got.
%05d means: If your integer number digit size will be less than 5 then it will append the 0 (zero) to make the number in 5 digit.
What about
int newnumber = 921*100000 + 2;
that gives 92100002. instead of 2 you can use any random number of course.
If you want to add zeros in front of the 921 so it becomes 0921 and for 1st September 0901 for example, you need to convert it to a string and check the length, and add zeros till you have the length that you want.
You could construct a String by such way:
String value = String.valueOf(randomNum); //your random num should have 5 digits or less
int N = 5; //your length
while (value.length < N)
value = "0" + value;
If you are going to store this as a string (which it seems you are already doing since you are adding 921 and 22334 and getting 92122334?) the easiest way would be to add 0's to the start of the string until it reaches a certain length.
StringBuilder numberString = new StringBuilder(maxSize);
numberString.append(yourNumber);
while(numberString.length() < maxSize)
numberString.insert('0');

String to binary?

I have a very odd situation,
I'm writing a filter engine for another program, and that program has what are called "save areas". Each of those save areas is numbered 0 through 32 (why there are 33 of them, I don't know). They are turned on or off via a binary string,
1 = save area 0 on
10 = save area 1 on, save area 0 off
100 = save area 2 on, save areas 1 and 0 off.
and so on.
I have another program passing in what save areas it needs, but it does so with decimal representations and underscores - 1_2_3 for save areas 1, 2, and 3 for instance.
I would need to convert that example to 1110.
What I came up with is that I can build a string as follows:
I break it up (using split) into savePart[i]. I then iterate through savePart[i] and build strings:
String saveString = padRight("0b1",Integer.parseInt(savePart[i]));
That'll give me a string that reads "0b1000000" in the case of save area 6, for instance.
Is there a way to read that string as if it was a binary number instead. Because if I were to say:
long saveBinary = 0b1000000L
that would totally work.
or, is there a smarter way to be doing this?
long saveBinary = Long.parseLong(saveString, 2);
Note that you'll have to leave off the 0b prefix.
This will do it:
String input = "1_2_3";
long areaBits = 0;
for (String numTxt : input.split("_")) {
areaBits |= 1L << Integer.parseInt(numTxt);
}
System.out.printf("\"%s\" -> %d (decimal) = %<x (hex) = %s (binary)%n",
input, areaBits, Long.toBinaryString(areaBits));
Output:
"1_2_3" -> 14 (decimal) = e (hex) = 1110 (binary)
Just take each number in the string and treat it as an exponent. Accumulate the total for each exponent found and you will get your answer w/o the need to remove prefixes or suffixes.
// will contain our answer
long answer = 0;
String[] buckets = givenData.split("_"); // array of each bucket wanted, exponents
for (int x = 0; x < buckets.length; x++){ // iterate through all exponents found
long tmpLong = Long.parseLong(buckets[x]); // get the exponent
answer = (10^tmpLong) + answer; // add 10^exponent to our running total
}
answer will now contain our answer in the format 1011010101 (what have you).
In your example, the given data was 1_2_3. The array will contain {"1", "2", "3"}
We iterate through that array...
10^1 + 10^2 + 10^3 = 10 + 100 + 1000 = 1110
I believe this is also why your numbers are 0 - 32. x^0 = 1, so you can dump into the 0 bucket when 0 is in the input.

Java comparing two letters

I ran in to a small problem while working on my assignment. Basically I'm making a small program that asks the user for 3 letters and compares them to 3 letters that are coded in. Then the program is supposed to compare the 3 letters and if they're the same then print true. Thus far I've been able to make it without problems using compareTo, but now the tricky part is that I need to add a "tolerance" to the program (which I have) but the tolerance is supposed to loop back from Z to A. So if tolerance is 3 and the user inputs X Y Z (when it really is A B C) it should still print out true.
NOTE: the Tolerance will not go above 3. ALSO, We shouldn't use Arrays.
Any ideas how I can accomplish this? If it's complicated to understand what I'm asking please post and I'll try to clarify it :)
Thanks
EDIT: basically this is the code that compares the tolerances
if ((a1.compareTo(d1) <= tolerance) && (a1.compareTo(d1) >= negTolerance)
&& (b1.compareTo(e1) <= tolerance) && (b1.compareTo(e1) >= negTolerance)
&& (c1.compareTo(f1) <= tolerance) && (c1.compareTo(f1) >= negTolerance))
{
open = true;
} else open = false;
where a1 - c1 are pre inputed characters and d1-f1 are user entered. tolerance is also user entered as an integer between 1 and 3
Since it's a homework assignment, I won't give you the full answer, but I'll give you a hint. You want to look at the character codes (ASCII) for the letters. This will let you solve the tolerance problem. You might also have to do some magic with % (modulus) to handle the looping back of Z to A.
EDIT
If you cannot use the ASCII values, the return value of compareTo will help you, but keep in mind that that comparing A to Z and Z to A will give you -25 and 25 respectively. This is where the % operator will help you.
I would recommend using the ASCII value of the char.
char[] expecteds = ...;
int tolerance = 3;
char input = ...;
int inputValue = char;
for (int i=0; i<expecteds.length; i++){
int delta = expected[0] - 'a' - input - 'a' % 'a';
if (i < tolerance)
result = true;
}
Use the Modulus (%) operator to cycle back around to the beginning:
int index = 0;
for (i in 1 .. 26) {
int index = (i+tolerance) % 26;
}
1) Map each character to a Number
2) Grab the tolerance
3) Add/subtract the tolerance from the number
4) Compare the letters in the tolerance range to the letter

Categories