Having a String representation of a number(no decimals), what's the best way to convert it to either one of java.lang.Integer or java.lang.Long or java.math.BigInteger? The only condition is that the converted type should be of minimal datatype required to hold the number.
I've this current implementation that works fine, but I would like to know if there's a better code without exception handling.
package com.stackoverflow.programmer;
import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
String number = "-12121111111111111";
Number numberObject = null;
try {
numberObject = Integer.valueOf(number);
} catch (NumberFormatException nfe) {
System.out.println("Number will not fit into Integer type. Trying Long...");
try {
numberObject = Long.valueOf(number);
} catch (NumberFormatException nfeb) {
System.out.println("Number will not fit into Long type. Trying BigInteger...");
numberObject = new BigInteger(number);
}
}
System.out.println(numberObject.getClass() + " : "
+ numberObject.toString());
}
}
From what you said, here is what I would have done:
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
public class TestSO09_39463168_StringToMinimalNumber {
public static void main(String[] args) {
List<String> strNumbers = Arrays.asList("0", //int
"123", //int
"-456", //int
"2147483700", // Long
"-2147483700", // Long
"9223372036854775900", //BigInt
"-9223372036854775900" //BigInt
);
for(String strNumber : strNumbers){
Number number = stringToMinimalNumber(strNumber);
System.out.println("The string '"+strNumber+"' is a "+number.getClass());
}
}
public static Number stringToMinimalNumber(String s){
BigInteger tempNumber = new BigInteger(s);
if(tempNumber.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 || tempNumber.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0){
return tempNumber;
} else if(tempNumber.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0 || tempNumber.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0){
return tempNumber.longValue(); //Autobox to Long
} else {
return tempNumber.intValue(); //Autobox to Integer
}
}
}
You must use a temporary BigInteger, or else you'll end up with lazarov's solution, which is correct, but you can't really do something like that for reason mentionned in the comments.
Anyway, every BigInteger (the ones that are not returned) will be garbage collected. As for autoboxing, I don't think it's that of a bad thing. You could also make "BigInteger.valueOf(Long.MAX_VALUE))" as a constant. Maybe the compiler or the JVM will do this on its own.
I'm not really sure of how efficient it is, and using only BigInteger might be a good idea (as Spotted did), because I serioulsy doubt it would really improve the rest of your code to use the right size, and it might even be error prone if you try to use these Numbers with each other ... But again, it all depend on what you need. (and yes, using Exception as flow control is a really bad idea, but you can add a try catch on the BigInteger tempNumber = new BigInteger(s); to throw your own exception if s is not a number at all)
For recreational purpose, I have made the solution without using a BigInteger, and only with String parsing (this is still not what I recommand to do, but it was fun :)
public static final String INT_MAX_VALUE = "2147483647";
public static final String LONG_MAX_VALUE = "9223372036854775807";
public static Number stringToMinimalNumberWithoutBigInteger(String numberStr){
//Removing the minus sign to test the value
String s = (numberStr.startsWith("-") ? numberStr.substring(1,numberStr.length()) : numberStr);
if(compareStringNumber(s, LONG_MAX_VALUE) > 0){
return new BigInteger(numberStr);
} else if(compareStringNumber(s, INT_MAX_VALUE) > 0){
return new Long(numberStr);
} else {
return new Integer(numberStr);
}
}
//return postive if a > b, negative if a < b, 0 if equals;
private static int compareStringNumber(String a, String b){
if(a.length() != b.length()){
return a.length() - b.length();
}
for(int i = 0; i < a.length(); i++){
if( a.codePointAt(i) != b.codePointAt(i) ){ //Or charAt()
return a.codePointAt(i) - b.codePointAt(i);
}
}
return 0;
}
Please don't use exceptions for handling flow control, this is a serious anti-pattern (also here).
As you mentionned in the comments, the real thing you've been asked is to convert a List<String> into a List<Number>.
Also, if I understand correctly, you know that:
You should encounter only numbers without decimals
The biggest value you can encounter is possibly unbound
Based on that, the following method will do the job in a more clever way:
private static List<Number> toNumbers(List<String> strings) {
return strings.stream()
.map(BigInteger::new)
.collect(Collectors.toList());
}
Eidt: if you're not very familiar with the stream concept, here's the equivalent code without streams:
private static List<Number> toNumbers(List<String> strings) {
List<Number> numbers = new ArrayList<>();
for (String s : strings) {
numbers.add(new BigInteger(s));
}
return numbers;
}
Well if you want to do it "by hand" try something like this:
We define the max values as strings :
String intMax = "2147483647";
String longMax = "9223372036854775807";
and our number:
String ourNumber = "1234567890"
Now our logic will be simple :
We will check lenghts of strings firstly
If our numbers length < int max length : IT IS INT
If our numbers length == int max length : Check is it INT or LONG
If our numbers length > int max length :
3.1 If our numbers length < long max length : IT IS LONG
3.2 If our numbers length == long max length : Check is it LONG or BIG INTEGER
3.3 If our numbers length > long max length : IT IS BIG INTEGER
The code should look something like this (I have not tried to compile it may have syntax or other errors) :
if(ourNumber.lenght() < intMax.length ){
System.out.println("It is an Integer");
} else if(ourNumber.lenght() == intMax.length){
// it can be int if the number is between 2000000000 and 2147483647
char[] ourNumberToCharArray = ourNumber.toCharArray();
char[] intMaxToCharArray = intMax.toCharArray();
int diff = 0;
for(int i = 0; i < ourNumberToCharArray.length; i++) {
diff = Character.getNumericValue(intMaxToCharArray[i]) - Character.getNumericValue(ourNumberToCharArray[i]);
if(diff > 0) {
System.out.println("It is a Long");
break;
} else if(diff < 0) {
System.out.println("It is an Integer");
break;
}
}
if(diff == 0){
System.out.println("It is an Integer");
}
} else {
if(ourNumber.lenght() < longMax.length()) {
System.out.println("It is a Long");
} else if(ourNumber.lenght() == longMax.length()){
char[] ourNumberToCharArray = ourNumber.toCharArray();
char[] longMaxToCharArray = longMax.toCharArray();
int diff = 0;
for(int i = 0; i < ourNumberToCharArray.length; i++) {
diff = Character.getNumericValue(longMaxToCharArray[i]) - Character.getNumericValue(ourNumberToCharArray[i]);
if(diff > 0) {
System.out.println("It is a BigInteger");
break;
} else if(diff < 0) {
System.out.println("It is a Long");
break;
}
}
if(diff == 0){
System.out.println("It is a Long");
}
} else {
System.out.println("It is a BigInteger");
}
}
Then logic that checks if the numbers match or not is the same in both cases you can but it in a function for example.
Related
Since last night I have been working very hard trying to write a solution to the problem "0-1 Sequences" (https://open.kattis.com/problems/sequences) on Kattis. At this point, I am at my wits end. I keep getting the wrong answer on the third test case, and I've tried everything I can possibly think of to fix my code. I'm fairly certain that the formula I am using to compute the result is correct, and I haven't been able to find an example where it gives the wrong answer. I suspect the issue is something to do with how I am calculating the modulus, but I've written and rewritten the relevant parts of the code and I am still failing each time. Below is my code (sorry in advance, I've been working like a madman with not much regard for writing "nice" code).
import java.util.*;
import java.util.ArrayList;
public class oneZeroSequences {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
//leading zero's have no effect on the number of inversions,
//and we therefore get rid of them all right off the bat.
while(s.charAt(0)=='0'){
s=s.substring(1);
if(s.length()==0){
System.out.println(0);
System.exit(0);
}
}
System.out.println(findSum(s));
System.exit(0);
}
public static long findSum(String s) {
int m=1000000007;
long res = 0;
//if passed an empty string, the sum of inversions is obviously 0
if(s.length()==0){
return 0;
}
while(s.charAt(0)=='0'){
s=s.substring(1);
if(s.length()==0){
return 0;
}
}
//if the first character of the string is a question mark, we handle the case
//where that question mark is 1 first, and then remove the question mark since
//leading 0's have no effect on inversions.
while(s.charAt(0)=='?'){
res+=findSum("1"+s.substring(1))%m;
s=s.substring(1);
if(s.length()==0){
return res%m;
}
}
ArrayList<Integer> qArray = new ArrayList<Integer>();
int start=0;
int found;
//here we construct an array of the indices of question marks in the string
while(true){
found=s.indexOf('?', start);
if(found==-1){
break;
}
qArray.add(found);
start=found+1;
}
ArrayList<Integer> zeroArray = new ArrayList<Integer>();
start=0;
found=0;
//here we construct an array of the indices of 0's in the string
while(true){
found=s.indexOf('0', start);
if(found==-1){
break;
}
zeroArray.add(found);
start=found+1;
}
long k = qArray.size();
long a = zeroArray.size();
long zeroSum = sumArrayList(zeroArray);
long qSum = sumArrayList(qArray);
Double dres = 0.0;
//the formula for sum of inversions is as follows:
//2^k*(zeroSum) + 2^(k-1)*(qSum) - (a^2-a)*2^(k-1) - (2a-1)*2^(k-2) - (k^2+k)*2^(k-3)
//the following lines of code apply this formula, taking the modulus at each step.
if(k>=3){
res += (expBySquaringMod(2, k)*(zeroSum%m))%m;
//res=(res%m+m)%m;
res +=((expBySquaringMod(2, k-1))*(qSum%m))%m;
//res=(res%m+m)%m;
res -= ((((((a%m)*(a%m))%m)-a%m)%m)*expBySquaringMod(2,k-1))%m;
//res=(res%m+m)%m;
res -= (((((2*a-1)%m)*(k%m))%m)*expBySquaringMod(2,k-2))%m;
//res=(res%m+m)%m;
res-= (((((k%m)*(k%m))%m+k%m)%m)*expBySquaringMod(2, k-3))%m;
//res=(res%m+m)%m;
return res%m;
}
//the expBySquaringMod function will give incorrect
//results for negative exponents, hence the following code.
dres += ((Math.pow(2,k))*(zeroSum%m))%m;
dres=(dres%m+m)%m;
dres +=((Math.pow(2,k-1))*(qSum%m))%m;
dres=(dres%m+m)%m;
dres -= (((((a%m)*(a%m))%m-a%m)%m)*(Math.pow(2,k-1)))%m;
dres=(dres%m+m)%m;
dres -=((((2*a-1)%m*(k%m)%m)*(Math.pow(2,k-2))))%m;
dres=(dres%m+m)%m;
dres-=((((k%m)*(k%m)%m+k%m))%m*(Math.pow(2,k-3)))%m;
dres=(dres%m+m)%m;
res+=dres.intValue()%m;
return res%m;
}
public static int sumArrayList(ArrayList<Integer> list) {
int res = 0;
for(int d : list) {
res+=d;
}
return res;
}
//this function was written to deal with the massive powers of two required for the solution
public static long expBySquaringMod(int base, long exp) {
int m=1000000007;
long res=1;
if(exp%2==0) {
for(int i=0; i<exp/2;i++) {
res=(res*base*base)%m;
}
} else{
res=base;
for(int i=0; i<exp/2;i++) {
res=(res*base*base)%m;
}
}
return res;
}
}
Any help will be greatly appreciated. This problem has been causing me a lot of distress.
So for this program, the mean and median are supposed to calculated and displayed but I do not think the data I am inputting is getting put into the array because it runs without error but does not display any data I have put into it.
public static double Mean(double[] gradeArray, int numGrades) {
double totalArray = 0.0;
double mean;
for (int i = 0; i < numGrades; i++) {
totalArray = gradeArray[i] + totalArray;
}
mean = totalArray / numGrades;
return mean;
}
public static double Median(double[] gradeArray, int numGrades) {
double median;
Arrays.sort(gradeArray, 0, numGrades);
if (numGrades % 2 == 0) {
median = ((gradeArray[(numGrades / 2)] + gradeArray[(numGrades / 2 + 1)]) / 2);
} else {
median = gradeArray[(numGrades / 2)];
}
return median;
}
private void Enter_Grades_ButtonActionPerformed(java.awt.event.ActionEvent evt) {
double[] totalArray = new double[25];
String text_box_input_str = null;
double text_box_input_num = 0;
int numGrades = 0;
String num_grades_str;
DecimalFormat df = new DecimalFormat("#0.0##");
do {
try {
text_box_input_str = JOptionPane.showInputDialog(null, "Enter Item Price", "Enter Price", JOptionPane.PLAIN_MESSAGE);
if (text_box_input_str == null || text_box_input_str.isEmpty()) {
return;
}
if (text_box_input_num > 0) {
double[] gradeArray = null;
gradeArray[numGrades] = text_box_input_num;
numGrades++;
num_grades_str = Integer.toString(numGrades);
num_grades_text.setText(num_grades_str);
Mean_Text.setText(df.format(Mean(gradeArray, numGrades)));
Median_Text.setText(df.format(Median(gradeArray, numGrades)));
}
} catch (NumberFormatException e) {
System.out.println("NumberFormatException caught");
JOptionPane.showMessageDialog(null, "You Must Input numeric data!", "Bad Data!", JOptionPane.ERROR_MESSAGE);
}
} while (text_box_input_str != null && !text_box_input_str.isEmpty());
}
I expect the program to calculate the data that is inputted and calculate the mean and median and then display the totals
it looks like text_box_input_num is set to 0, never updated, but then there is an if check if it's > 0
Rather than pointing out the problem with your code directly, I'll give some pointers on how to find it yourself.
break your code down into smaller parts
for each part, write both the method and the tests that prove the method does what you expect
once the individual parts are working, write the method (and tests) that use them.
You'll end up with several methods with names like getValues, hasValue, printError, checkValidValue, showMedian etc. all of which do exactly what you want.
I guarantee that if you do that it'll become pretty clear very quickly what's wrong.
For a homework assignment I'm working on you're required to create a custom LinkedList data structure to hold the terms of a polynomial. I'm having a problem at the moment with my constructor adding terms to the data structure because it needs to accept a string like "5.2 3 2.1 2" (which would be the equivalent of 5.2^3 + 2.1^2) and store it in the my custom LinkedList. Some of the requirements include that terms cannot have coefficients of zero, exponents must be integers, and coefficients can be either integers or doubles. When I trace the program using my IDE's debugger what I've seen is that for some reason valid coefficients are getting caught on the clause that I've marked with a "#" and the reference to the head of my list (the Term first variable) doesn't seem to be getting additional variables from the inputted string linked to it properly. Any help you can give would be much appreciated, thanks in advance. There are many required methods but this the relevant code for the problem I'm experiencing:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Polynomial
{
// instance variables
private Term first;
private int numTerms;
/**
* Constructor for objects of class Polynomial
*/
public Polynomial(String s)
{
Pattern whiteSpace = Pattern.compile(" ");
String[] poly = whiteSpace.split(s);
double coefficient;
int exponent;
if(poly.length % 2 == 1) {
throw new IllegalArgumentException();
}
first = new Term(); // dummy variable so that checking the first term specially is unnecessary
for(int term = 0; term < poly.length; term += 2) {
if(poly[term].matches("[\\-][0-9]||[0-9]||[0-9][\\.][0-9]||[\\-][0-9][\\.][0-9]")) {
coefficient = Double.parseDouble(poly[term]);
if(poly[term + 1].matches("[0-9]")) {
exponent = Integer.parseInt(poly[term++]);
} else {
throw new IllegalArgumentException(); //#
}
numTerms++;
this.addTerm(coefficient, exponent);
}
}
}
public void addTerm(double coef, int exp)
{
if(coef == 0) {
throw new IllegalArgumentException();
}
Term pointer = first;
while(pointer.next != null) {
if(exp == pointer.next.exponent) {
if(coef + pointer.next.coefficient == 0) {
pointer.next = pointer.next.next;
numTerms--;
} else {
pointer.next.coefficient += coef;
break;
}
} else if(pointer.next.exponent < exp) {
Term newTerm = new Term(coef, exp, pointer.next.next);
pointer.next = newTerm;
numTerms++;
break;
}
pointer = pointer.next;
}
}
private class Term {
double coefficient;
int exponent;
Term next;
Term() {
next = null;
}
Term(double coef, int exp, Term nextTerm) {
coefficient = coef;
exponent = exp;
next = nextTerm;
}
}`
You do not need regex to check for validity ParseXXX() takes care of that. If parsing fails, an Exception is thrown and then you can simply throw IllegalArgumentException
for (int term = 0; term < poly.length - 1; term += 2) {
try {
coefficient = Double.parseDouble(poly[term]);
exponent = Integer.parseInt(poly[term + 1]);
numTerms++;
this.addTerm(coefficient, exponent);
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
}
Moreover, using regex = "[0-9]" means only a single digit exponent. You might want to change it to "[0-9]+"
I am aware there are multiple threads like my assignment below, but I just can't figure it out. I can't exactly figure out the mistake. Help would be appreciated.
I am trying to do this program:
Everything works fine unless I input the same chains or similar (for example ACTG and ACTG or ACTG and ACTGCCCC), when it tells me
string index out of range
This is that part of my code:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if (canConnect(s,l)) {
tries+=1;
k+=1;
}
}
if (tries==shortDNA.length()-1) {
pos=i-1;
break;
}
}
Let's call the two DNA strings longer and shorter. In order for shorter to attach somewhere on longer, a sequence of bases complementary to shorter must be found somewhere in longer, e.g. if there is ACGT in shorter, then you need to find TGCA somewhere in longer.
So, if you take shorter and flip all of its bases to their complements:
char[] cs = shorter.toCharArray();
for (int i = 0; i < cs.length; ++i) {
// getComplement changes A->T, C->G, G->C, T->A,
// and throws an exception in all other cases
cs[i] = getComplement(cs[i]);
}
String shorterComplement = new String(cs);
For the examples given in your question, the complement of TTGCC is AACGG, and the complement of TGC is ACG.
Then all you have to do is to find shorterComplement within longer. You can do this trivially using indexOf:
return longer.indexOf(shorterComplement);
Of course, if the point of the exercise is to learn how to do string matching, you can look at well-known algorithms for doing the equivalent of indexOf. For instance, Wikipedia has a category for String matching algorithms.
I tried to replicate your full code as fast as I could, I'm not sure if I fixed the problem but you don't get any errors.
Please try it and see if it works.
I hope you get this in time and good luck!
import java.util.Arrays;
public class DNA {
public static void main(String[] args) {
System.out.println(findFirstMatchingPosition("ACTG", "ACTG"));
}
public static int findFirstMatchingPosition(String shortDNA, String longDNA) {
int positionInLong = 0;
int positionInShort;
while (positionInLong < longDNA.length()) {
positionInShort = 0;
while(positionInShort < shortDNA.length()) {
String s = shortDNA.substring(positionInShort, positionInShort + 1);
if(positionInShort + positionInLong + 1 > longDNA.length()) {
break;
}
String l = longDNA.substring(positionInShort + positionInLong, positionInShort + positionInLong + 1);
if(canConnect(s, l)) {
positionInShort++;
if(positionInShort == shortDNA.length()) {
return positionInLong;
}
} else {
break;
}
}
positionInLong++;
if(positionInLong == longDNA.length()) {
return -1;
}
}
return -1;
}
private static String[] connections = {
"AT",
"TA",
"GC",
"CG"
};
private static boolean canConnect(String s, String l) {
if(Arrays.asList(connections).contains((s+l).toUpperCase())) {
return true;
} else {
return false;
}
}
}
I finally changed something with the k as Faraz had mentioned above to make sure the charAt does not get used when k overrides the length of the string and the program worked marvelously!
The code was changed to the following:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
if (k<longDNA.length()) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if ((s=='A' && l=='T') || (s=='T' && l=='A') || (s=='G' && l=='C') || (s=='C' && l=='G')) {
tries+=1;
k+=1;
}
}
}
if (tries==shortDNA.length()) {
pos=i;
break;
}
}
I am not sure how aesthetically pleasing or correct this excerpt is but - it completely solved my problem, and just 2 minutes before the deadline! :)
A huge thanks to all of you for spending some time to help me!!
import java.util.*;
class A{
static int count=0;
static String s;
public static void main(String z[]){
int n;
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
System.out.println(noOfBouncy(n));
}
public static int noOfBouncy(int k){
int limit=(int)Math.pow(10,k);
s=new String("1");
int num=Integer.parseInt(s);
while(num<limit){
if(isIncreasing(s) || isDecreasing(s) ){
}
else{
count++;
}
num++;
s=new String(Integer.toString(Integer.parseInt(s)+1));
}
count=limit-count;
return count;
}
}
public static boolean isIncreasing(String s){
int len=s.length();
for(int i=0;i<len-1;i++){
if(s.charAt(i)>s.charAt(i+1)){
return false;
}
}
return true;
}
public static boolean isDecreasing(String s){
int len=s.length();
for(int i=0;i<len-1;i++){
if(s.charAt(i)<s.charAt(i+1)){
return false;
}
}
return true;
}
I have given the definitions to the two functions used isIncreasing() & isDecresing()
The program runs well for the value of n<7 but does not respond for values above it, Why ?
I accept the programming style is very immature,please ignore.
I've tried to execute it with n=7 and it finishes in 810ms, returning 30817.
However, I recommend to you to optimize the performance of your program by saving unnecessary object instantiation: It will be better if you maintain the counter in num, and convert it to string just once, at the beginning of the loop:
int num=1;
while (num < limit)
{
s=Integer.toString(num);
if (isIncreasing(s) || isDecreasing(s))
{
}
else
{
count++;
}
num++;
}
Like this it takes just 450ms to finish.
The program was not actually stuck but it is taking way too much time to complete its execution when value of 'n' is larger.
So now the question is, I need to optimize the code to take minimum time #Little have an optimization bit that's not enough.
Any hint would be appreciable.
To increase the performance you should avoid the conversation to String and do the check with numbers.
As it doesn't matter for the result if you start the comparison from left to right or from right to left one computational solution could be.
as pseudo code
1) compare the value of the right most digit with the digit on it's left
2) is it lower --> we found a decreasing pair
3) else check if it is bigger --> we found an increasing pair
4) else --> not a bouncy pair
5) if we found already one decreasing and one increasing pair it's bouncy number
6) divide the number by ten if it's bigger then ten repeat with step 1)
The method to check if it's a bouncy number could look like this
static boolean isBouncyNumber(int number) {
boolean increasingNumber = false;
boolean decreasingNumber = false;
int previousUnitPosition = number % 10;
int remainder = number / 10;
while (remainder > 0) {
// step 1
int currentUnitPosition = remainder % 10;
if (currentUnitPosition > previousUnitPosition) {
// step 2
decreasingNumber = true;
} else if (currentUnitPosition < previousUnitPosition) {
// step 3
increasingNumber = true;
}
// step 5
if (decreasingNumber && increasingNumber) {
return true;
}
// step 6
previousUnitPosition = currentUnitPosition;
remainder = remainder / 10;
}
return decreasingNumber && increasingNumber;
}