Optimizing adding zero padding in a number - java

I'm practicing on how to optimize codes so any suggestion would be much appreciated. I have this method that adds zero padding to a number when its being incremented. The code are as follows:
public class CommonAlgorithm {
NumberRetrieve retrieve;
public long incrementNumber(CommonNumber t) {
CommonNumberFacade facade = new CommonNumberFacade(retrieve.apply(t));
String number = facade.getGeneratedNumber();
Long num = Long.parseLong(number);
num++;
String result = "";
if (String.valueOf(num).length() < number.length()) {
int length = number.length() - String.valueOf(num).length();
String zero = "";
for (int i = 0; i < length; i++) {
zero += "0";
}
result = zero + num;
} else {
result = String.valueOf(num);
}
return Long.parseLong(t.getPrefix()+result);
}
}
Are there more ways to optimize the code above?
Just in case anyone asks for the purpose of the function, the premise goes like this:
The function returns a number that is composed of the following: a 'prefix' and a 'number'. These two are concatenated to each other after the number has been incremented by 1. However, I realized that if the value of the number has zero padding in it, those zeroes will be disappear once they are converted into a long data type. Therefore if the following values are applied:
prefix = 123
number = 000001
The return value will be 1232 instead of 123000002. That is the problem that the function above is solving. I can't change the return type of the facade.generatedNumber() function into long as I need to return that String return type somewhere in my project eventually. I hope you could give a couple of suggestions

You can simplify your if-else statement as follows:
StringBuilder sb = new StringBulder();
String numStr = String.valueOf(num);
for (int i = numStr.length(); i < number.length(); i++) {
sb.append('0');
}
sb.append(numStr);
String result = sb.toString();

A few simple things:
You use String objects to build your results, like zero and result. Those could be StringBuilder objects. That would clearly express your intent to build strings!
You could look into using String.format()
You are invoking String.valueOf(num); three times, for the same num. You could do that once initially, and reuse that value, instead of computing it repeatedly.

Use the numerical primitive type long instead of the Object wrapper Long.
long num = Long.parseLong(number);
num++;
Place the string representation of num in its own variable.
String numStr = String.valueOf(num);
Zero padding to keep the number of original digits is only needed for increments for negative numbers, and then only for carries / digits '0'. This means that the zeroes should go after the sign.
String +, += is costly, use a StringBuilder:
StringBuilder sb = new StringBuilder(number.length());
Optimal is a relative, it would be okay to do:
long num = Long.parseLong(number);
++num;
String paddedNumStr = numStr.length >= number.length() ? numStr
: String.format("%" + number.length() + "d", num);
Using an if-expression as heuristic optimisation for 95% of the cases.

Related

It works if use 'int' but fails when I use 'long' . How do I make this function return long

the function only returns value when I declare 'n' as int, but returns null when i use 'long'.
Given a string and a value n, the string should be concatenated n number of times. in the concatenated string, we will take the first n characters in that string and return the number of letter 'a' that appeared.
Print a single integer denoting the number of letter a's in the first n letters of the infinite string created by repeating s infinitely many times.
In this function, two parameters are passed, a string and a long value. The code works very well if use an int value instead of long. Please how do i fix this long and int issue ?
public class StringLettersRepeat {
static long repeatedString(String s, long n) {
String string = "";
int count =0;
for(int i=0; i<n; i++){
string+=s;
}
char[] strChar = string.toCharArray();
char[] result = new char[(int) n];
for(int i=0; i<strChar.length;i++){
result[i]=strChar[i];
}
for(char str : result){
if('a'==str){
count++;
}
}
return count;
}
public static void main(String[] args) {
long result = repeatedString("a", 1000l);
System.out.println(result);
}
}
I expect the output to return a value, which is the number of count.
for example, if I enter string "aba" and n=7, it should return 5.
But if i pass in a string, say 'a' with n=100000000000, it's supposed to return 100000000000 but it doesn't work. Please what's possibly wrong with my code?
Given your example of calling repeatedString("aba", 7), the resulting string would be "abaabaa", and has 5 a's, as you said.
But, you don't actually have to build that result string. Instead, realize that the result string is the original string repeated 2 times, plus the first 1 characters of the string, both of which can easily be calculated using division and remainder math:
long repeats = n / s.length();
long extra = n % s.length();
Now, if you count the number of a's in the string, you can multiply by repeats. You don't need to repeat the counting operation. If you then also count the number of a's in the first extra characters of string, you have your final result.
int countFull = 0, countExtra = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'a') {
countFull++;
if (i < extra)
countExtra++;
}
}
Then calculate the total and return it:
return countFull * repeats + countExtra;
This code also runs a lot faster, because you only have to iterate s once, it doesn't matter for performance what n is, and you don't copy any characters, so it also uses a lot less memory. It actually doesn't use any memory.
Big-O is:
Performance: O(m) where m is length of input string.
Memory: O(1)
Neither is related to n.
Test
System.out.println(repeatedString("aba", 7));
System.out.println(repeatedString("a", 100000000000L));
Output
5
100000000000

How to print a random character from a string?

I have an assignment due and the last part of the assignment asks:
Suppose s is any string. Write a sequence of statements that will print a random character from s.
Here is what I have come up with so far:
for(int j = 0; j < s.length(); j++){
}
int l = ((int)Math.random()*s.length());
char ch = s.charAt(l);
System.out.println(ch);
I think these are the basic concepts I need to learn how to understand/use to write this code successfully. What I am confused on is where these specific lines of code go, for example if the charAt method should come before the loop, etc.
You almost had it already. I think your main issue was this part:
int l = ((int)Math.random()*s.length());
Your (int) cast is misplaced. If you read the javadoc of Math.random() you see that it returns a double value "greater than or equal to 0.0 and less than 1.0". Casting values of this range to int (i.e. simply cutting off all decimal places) will always result in 0, which only prints the first character of the string.
The solution is to first multiply it with the string's length and do the cast afterwards:
int l = (int)(Math.random()*s.length());
If you only want to print one random character, you don't need a loop of any sort, so you can delete that from your code.
See this fiddle for a working example. What you still need to do is think about how to get the input string (hint: maybe read it from System.in).
public static void main (String[] args) throws java.lang.Exception
{
String s = "foobar42";
int l = (int)(Math.random()*s.length());
char ch = s.charAt(l);
System.out.println(ch);
}
And to finally show off in class, you could also have a look at the Random class which could replace the above line with something like
int l = new Random().nextInt(s.length());
and see if you can grasp the difference between those two approaches. Although that is completely irrelevant to your assignment and way out of scope.
You can get a random character by using s.charAt(x), where x is a random number between 0 and the length of the String-1.
The code for this is as follows:
String s = "text string";
Random rand = new Random();
int randomIndex = rand.nextInt(s.length());//returns a random number between 0 and the index of the last character of the string
System.out.println(s.charAt(randomIndex));
When you need to do this several times, you just put it in a loop like this:
String s = "text string";
for(int i = 0; i < 10; i++) { //prints 10 random characters from the String
Random rand = new Random();
int randomIndex = rand.nextInt(s.length());//returns a random number between 0 and the index of the last character of the string
System.out.println(s.charAt(randomIndex));
}
Try this approach:
String s = "hello world";
System.out.println(Character.toString(s.charAt((new Random()).nextInt(s.length()))));
the s.length() returns the size of s;
the (new Random()).nextInt returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive);
the s.charAt returns the character at the position specified
the Character.toString returns the string representation of the specified character
I would do it like this:
System.out.println(s.charAt((int)(Math.random() * s.length())));

Multiplying a numeric string in java

I'm a beginner in programming and I've been doing the Project Euler programming problems to practice, I've been able to make my way so far, but this time I had to ask for help. Without spoilers, the problem I'm trying to solve consists of finding the sum of the digits of a very large number, so I can't hold it in an int or a double. So I made this method to multiply two strings containing a numeric value.
private static String multiply(String a, String b) {
// No, I'm not checking if the strings are numeric
int subTotal = 1, extra = 0;
String waitingString = "";
StringBuilder number1 = new StringBuilder(a);
StringBuilder number2 = new StringBuilder(b);
List<String> numbers = new ArrayList<String>();
// The reason I reverse the numbers is the for() loops
// I don't want to count down through the numbers, that
// would just confuse me more.
number1.reverse();
number2.reverse();
for (int i = 0; i < number1.length(); i++) {
waitingString = "";
subTotal = Character.getNumericValue(number1.charAt(i));
for (int j = 0; j < number2.length(); j++) {
subTotal *= Character.getNumericValue(number2.charAt(j));
subTotal += extra;
char[] temp = String.valueOf(subTotal).toCharArray();
waitingString = temp[temp.length - 1] + waitingString;
if (subTotal >= 10 || ((j == number2.length() - 1) && (String.valueOf(subTotal).length() > 1))) {
extra = Integer.parseInt(String.valueOf(subTotal).substring(0, temp.length - 1));
} else {
extra = 0;
}
subTotal = Character.getNumericValue(number1.charAt(i));
}
for (int k = 0; k < i; k++) {
waitingString += "0";
}
waitingString = extra + "" + waitingString;
numbers.add(waitingString);
}
// sumAll() is not the problem just in case you were wondering.
// Because as you've read the code, I'm passing a List<String>
// to it and as I was trying to find the error I printed the list
// before everything to check the values and the error was already
// there, 3 of the values are wrong.
return sumAll(numbers);
}
When testing I'm multiplying this number by itself: 1125899906842624. The result should be 1267650600228229401496703205376. But I'm getting 1267650600228229401607703205376. That's a difference of 111000000000. I've been trying to find the error for 2 days and i just can't.
I'm not looking for alternative or better ways to do this, I just can't find the error in my code that adds more than it should.
If you need to see the rest of the code I can provide it and please don't mind spelling/grammar errors, english is not my native language.
Without trying to run this or look at it under a debugger: it looks like you're setting up an extra variable which is a carry, i.e. the value which should get added to the next product as you move to the left (in your original numbers, not the reversed ones). One problem I can see is that if the last product in your inner loop produces something greater than or equal to 10, you compute extra; but then when you go the next outer loop, extra still has that value and gets added to subTotal when it shouldn't be. Try adding the statement extra = 0; at the beginning of your outer loop, and before the inner loop starts. That may fix the problem.
P.S. You're making a lot of extra work for yourself by representing the subTotal as a string and working with it. While I understand why you'd want to use strings for the two multiplicands and the product, subTotal is the product of two single digits with a carry added, and it can never be greater than 89. So you should never have to convert it to a string and work with the string. Thus, instead of
char[] temp = String.valueOf(subTotal).toCharArray();
waitingString = temp[temp.length - 1] + waitingString;
you could say
waitingString = String.valueOf(subTotal % 10) + waitingString;
or something similar (subTotal % 10 gives the remainder when subTotal is divided by 10, and is therefore the last digit of subTotal); and instead of the complex code to compute extra, just say
extra = subTotal / 10;
which divides by 10 and throws away the remainder. You shouldn't be computing String.valueOf(subTotal) at all.
PPS. Don't worry about the answers that tell you to use BigInteger. If you were doing a real programming project, that's what you'd use. But for someone learning how to program, I think that writing a program to compute the product of two numbers, the long way, is a good learning tool.
As someone commented, this would probably be a job for the BigInteger class. Just say
BigInteger intA = new BigInteger(a)
BigInteger intB = new BigInteger(b)
and then call
intA.multiply(intB)
and that will get you a BigInteger containing the result.
I would use BigInteger like this
private static String multiply(String a, String b) {
if (a == null || b == null) {
if (b != null) return b;
return a;
}
BigInteger v = new BigInteger(a, 10);
if (v != null) {
BigInteger t = new BigInteger(b, 10);
if (t != null) {
BigInteger r = v.multiply(t);
return r.toString();
}
}
return "";
}
public static void main(String[] args) {
String result = multiply("1125899906842624", "1125899906842624");
String good = "1267650600228229401496703205376";
System.out.println(result.equals(good));
}
Which prints true when I run it.

Convert a string of numbers to an array in Java, where each number is a different slot

Suppose I have a string of 123456789. I would like to split this string and each number goes in a different slot in the array. I can't use the split() method because there is nothing to split on. How would I accomplish this in Java.
int x=123456789;
char[] array = x.toString().toCharArray();
int intarray[] = new int[array.length];
for (int i = 0; i < array.length; i++) {
intarray[i] = Integer.parseInt(array[i]);
}
And after this you intarray will be array of your numbers.
If your integer can be negative too, you must take it's absolute value and make same operations, and after that multiple first array value by -1. But I guess, it's not needed.
EDIT:
I think, I don't understand your question properly. If you want to split only string, you must use this lines only. I wrote about integers,which might be helpful too.
string x="123456789";
char[] array = x.toCharArray();
If you're only dealing with non-negative integers, the toCharArray() method should be suitable for you. It gives you the string as an array.
The String class has a neat method for doing this, toCharArray().
You can use the following to avoid creating Strings.
long x = x;
ByteBuffer bb = ByteBuffer.allocate(18);
if (x == 0) {
bb.put((byte) 0);
} else {
while (x > 0) {
bb.put((byte) (x % 10));
x /= 10;
}
}
int len = bb.position();
byte[] digits = new byte[len];
for (int i = 0; i < len; i++)
digits[i] = bb.get(len - i - 1);
is it compelsory that the data will be of single digit ?If the data may come in multiple digits then it will not be possible to identify whether the numeric value is of single digit of multiple digit ?
e.g. if it is 12(twelve) then if all string is 512 then how will you identify whether to represent 512 as 5,1,2 or 5,12 ?
if it is fix that the numbers will be in single digits and non negetives then toCharArray() of String class will work for you

I want to be able to convert numbers into text according to the ASCII decimal table

I am trying to make it so that I can take individual three-character substrings and convert them to integers under the conditions tht the length of the String is a multiple of three. The integers into which the partioned substrings are converted are supposed to function as relative positions in an array that contains all the printing characters of the ASCII table.
String IntMessage = result.toString();
if
{
(IntMessage.substring(0,1)=="1" && IntMessage.length()%3==0)
for(j=0;j < IntMessage.length()-2;j += 3)
n = Integer.parseInt(IntMessage.substring(j,j+3));
mess += ASCII[n-32];
return mess;
Under otherwise conditions, the method should take the first two characters of the String and initialize them to a variable i. In this case, the variable mess is initialized to the character in the ASCII array with an index of i-32. Then there is a for loop that takes the remaining characters and partitions them into three-digit substrings and they are taken and changed into strings according to their corresponding positions in the ASCII array. The String variables in this array are continuously added on to the the variable mess in order to get the BigInteger to String conversion of the IntMessage String.
int i = Integer.parseInt(IntMessage.substring(0,2));
mess=ASCII[i-32];
for(l=2; l< IntMessage.length() - 2; l+=3)
r = Integer.parseInt(IntMessage.substring(l,l+3));
mess+=ASCII[r-32];
return mess;
For some reason the method isn't working and I was wondering whether I was doing something wrong. I know how to take an input String and convert it into a series of numbers but I want to do the opposite also. Is there anyway you could help?
Based on your description you can use the following methods:
String fromIntMessage(String msg) {
StringBuilder result = new StringBuilder();
for (int x = (msg.length() % 3 - 3) % 3; x < msg.length(); x += 3) {
int chr = Integer.parseInt(msg.substring(Math.max(x, 0), x + 3));
result.append(Character.toString((char) (chr - 32)));
}
return result.toString();
}
String toIntMessage(String string) {
StringBuilder result = new StringBuilder();
for (char c : string.toCharArray()) {
result.append(String.format("%03d", c + 32));
}
return result.charAt(0) == '0' ? result.substring(1) : result.toString();
}
which will give you
toIntMessage("DAA") // => "100097097"
fromIntMessage("100097097") // => "DAA"

Categories