I want to evaluate an expression like -4-12-2*12-3-4*5 given in a String form without using API as I am a beginner and want to grasp the logic.
Given below is my unsuccessful attempt to this problem which, if you may like, ignore and suggest appropriate logic.And of course your codes are also welcome :-)
public class SolveExpression3 {
static String testcase1 = "-4-12-2*12-3-4*5";
public static void main(String args[]){
SolveExpression3 testInstance= new SolveExpression3();
int result = testInstance.solve(testcase1);
System.out.println("Result is : "+result);
}
public int solve(String str){
int sum = 1;
int num1 = 0;
int num2 = 0;
String num = "";
int len = str.length();
System.out.println(str);
for (int i = len-1 ; i >= 0; i--)
{
char ch = str.charAt(i);
if(ch == '*')
{
String s = "";
num1 = num2 = 0;
//to get the number on left of *
for (int j = i; j >= 0; j--)
{
char c = str.charAt(j);
if(c == '+' || c == '-' || j == 1)
{
num1 = stringToInt(s);
s = "";
break;
}
else
{
s = c + s;
}
}
//to get the number on right of *
for (int j = i; j <= len; j++)
{
char c = str.charAt(j);
if(c == '+' || c == '-' || j == len-1)
{
num2 = stringToInt(s);
s = "";
break;
}
else
{
s = c + s;
}
}
sum = sum + num1*num2;
}
else
{
num = ch + num;
}
}
len = str.length();
for (int i = len-1; i >= 0; i--)
{
char ch = str.charAt(i);
if(ch==' ')
{}
else if(ch=='+')
{
sum = sum + stringToInt(num);
num = "";
}
else if(ch=='-')
{
sum = sum - stringToInt(num);
num = "";
}
else
{
num = ch + num;
}
}
return sum;
}
public int stringToInt(String str)
{
int number=0;
for(int i = 0; i < str.length(); i++)
{
int num = str.charAt(i) - 48;
number = number*10+num;
}
return number;
}
}
found=true;
static String testcase1 = "-4-12-2*12-3-4*5";
Pattern SEGMENT_PATTERN = Pattern.compile("(\\d+(\\.\\d+)?|\\D+)");
/*\\d-means digit,
\\.-point,
+-one or more times,
?-optional and
\\D-non digit ch*/
Matcher matcher = SEGMENT_PATTERN.matcher(testcase1);
while (found) {
boolean Found = matcher.find();
String segment = matcher.group();//representing a number or an operator
if (Character.isDigit(segment.toCharArray()[0])) {
//is digit
}
else {
//is operator
}
}
This a a solution using a patter to determine if you have a number or and operator,u just have to adapt it a little to your case to computing the result.
You can add all the matches found to an array list than traverse it and test the operators and computer the result.
It works for floating numbers too,ex:"it matches 5.10".
I would suggest a different logic for your purpose.
Usually the logic behind programs algorithms is not different from the logic that you will apply if you have to do the task by hand.
For an expression like your example you would usually do:
Find all the *
For each * compute the result of the operation
Repeat steps 1 and 2 for + and -
Try to implement a recursive descent parser, a tutorial depicting how a calculator can be implemented (in Python but the same concepts apply to java) can be found here http://blog.erezsh.com/how-to-write-a-calculator-in-70-python-lines-by-writing-a-recursive-descent-parser/
Related
I was given this problem in an interview, return the output of this String s = "4+8×2" , output = 20, Ex2: String s = "3×7-4", output = 17.
This is my approach, but I am not able to get the expected result, please point out the correct way here.
public static int findResult (String s) {
int i = 0;
Stack<String> stack = new Stack<>();
while (i < s.length()) {
if (s.charAt(i) == '+') {
stack.push(String.valueOf(s.charAt(i)));
i++;
} else if (s.charAt(i) == '*') {
stack.push(String.valueOf(s.charAt(i)));
i++;
} else if (s.charAt(i) == '-') {
stack.push(String.valueOf(s.charAt(i)));
i++;
} else if (Character.isDigit(s.charAt(i))) {
int num = s.charAt(i) - '0';
while (i+1 < s.length() && Character.isDigit(s.charAt(i + 1))) {
num = num * 10 + s.charAt(++i) - '0';
}
stack.push(String.valueOf(num));
i++;
}
}
int current = 0;
//second while loop
while (!stack.isEmpty()) {
int firstNumber = Integer.parseInt(stack.pop());
if (stack.isEmpty()) return current;
String sign = stack.pop(""
//int firstNum = Integer.parseInt(stack.pop());
if (sign.equals("*")) {
current = firstNumber * Integer.parseInt(stack.pop());
stack.push(String.valueOf(current));
}
else if (sign.equals("-")) {
current = firstNumber;
stack.push(String.valueOf(current));
} else {
current = firstNumber + Integer.parseInt(stack.pop());
stack.push(String.valueOf(current));
}
}
return Integer.parseInt(stack.pop());
}
This is how I approached this problem. (It is somewhat similar to yours). I'll post the code first, then explain the process below:
import java.util.*;
class Main {
public static void main(String[] args) {
System.out.println(findResult("2*57-38*3/5-5-2+3*4/2-2-2"));
}
public static double findResult (String s){
String sub = s;
ArrayList<Double> nums = new ArrayList<Double>();
ArrayList<Character> operations = new ArrayList<Character>();
for(int x = 0; x < s.length(); x++){
if(s.charAt(x) == '+' || s.charAt(x) == '-' || s.charAt(x) == '*' || s.charAt(x) == '/' ){
operations.add(s.charAt(x));
int subInd = sub.indexOf(s.charAt(x));
nums.add(Double.valueOf(sub.substring(0,subInd)));
sub = sub.substring(subInd + 1);
}
}
nums.add(Double.valueOf(sub));
String[] operationTypes = {"*/","+-"};
for(int i = 0; i < 2; i++){
for(int j = 0; j < operations.size(); j++){
if(operationTypes[i].indexOf(operations.get(j)) != -1){
double val;
if(operations.get(j) == '*'){
val = nums.get(j) * nums.get(j+1);
}
else if(operations.get(j) == '/'){
val = nums.get(j) / nums.get(j+1);
}
else if(operations.get(j) == '+'){
val = nums.get(j) + nums.get(j+1);
}
else{
val = nums.get(j) - nums.get(j+1);
}
nums.set(j,val);
nums.remove(j+1);
operations.remove(j);
j--;
}
}
}
return nums.get(0);
}
}
Yeah...it's a lot:
The first step in this process was to divide the String into two ArrayLists: nums and operations. nums stores the terms and operations stores the..operations (*, /, +, -).
Now, we iterate through each "group" of operations, that being multiplication and division, and addition and subtraction.
Starting with mult/div, if we see either a '*' or '/' in our operations, then we compute the product or quotient of the corresponding elements in our nums and edit nums accordingly by modifying the element that matches indexes with the operation and deleting the term following it. Make sure you also remove the operation from nums and decrement the counter variable so the loop does not skip any values.
Finally, we will return the only value left in our nums which will be our answer.
I hope this helped you! Please let me know if you need any further details or clarification :)
I was wondering how to iterate over a string and to check how many hi's come out
For example, if the string is "hihi" the count should output 2.
This is what I have so far
public static int countHi(String str) {
int counter = 0;
for (int i = 0; i < str.length(); i++) {
if (str.substring(i, i + 1) == "h") {
if (str.substring(i, i + 1) == "i") {
counter = counter + 1;
}
}
}
return counter;
}
public static void main(String[] args) {
String str = "hihi";
int i = countHi(str);
System.out.println("number of hi = " + i);
}
You compare instances (like String) with .equals (not ==). However, here you can use == with String.charAt(int). Also, I would start with the second character and compare the character at the current index with i and the previous index with h. Like,
public static int countHi(String str) {
int counter = 0;
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i - 1) == 'h' && str.charAt(i) == 'i') {
counter++;
}
}
return counter;
}
Alternatively, compare the character at the current index with h and the character at the next index with i (but now you need to stop iterating a character earlier). Like,
public static int countHi(String str) {
int counter = 0;
for (int i = 0; i < str.length() - 1; i++) {
if (str.charAt(i) == 'h' && str.charAt(i + 1) == 'i') {
counter++;
}
}
return counter;
}
Here's the easy way:
public static int countHi(String str) {
return split(str, -1).length - 1;
}
Note that you must pass -1 as the second parameter of split(); without it, trailing blanks would be pruned from the result.
For compactness and readability, maybe:
int count = 0;
Matcher matcher = Pattern.compile(“hi”).matcher(string)
while (matcher.find()) {
count++;
}
This approach will work for any Regular Expression pattern, although it won’t be the most efficient.
I'm trying to build a function, that gets a string of letters, and prints the amount of each letter in the string.
for example:
input: String = "aaabbaccxyxyx"
output: 4a2b2c3x2y
This is what I've come up with:
public class Q1 {
public static String numLetters(String s){
String end = new String();
int counter = 0;
char c,d;
for(int i=0; i<s.length();i++){
c = s.charAt(i);
for(int j=0; j<s.length();j++){
d = s.charAt(j);
if(c == d){
counter++;
}
}
end = end + counter+c;
counter = 0;
}
return end;
}
but, this is the output: 4a4a4a2b2b4a2c2c3x2y3x2y3x
A lot of repeats..
Any help how to make it right?
Keep in mind, the function needs to return a string, not just prints it out.
Thanks! =)
I would make an int array to keep the count of each letter in in the string. Because there are 26 letters, the length of the array should be 26:
public static String numLetters(String s) {
int[] count = new int[26];
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
count[(int)(c - 'a')]++;
}
String ans = "";
for (int i = 0; i < 26; i++) {
if (count[i] != 0) {
ans += String.valueOf(count[i]) + (char)(i + 'a');
}
}
return ans;
}
A straightforward variant could look like this:
public static String countChars(String arg) {
String res = "";
boolean[] counted = new boolean[arg.length()];
for (int i = 0; i < counted.length; i++) {
if (!counted[i]) {
char c = arg.charAt(i);
int counter = 1;
for (int j = i + 1; j < counted.length; j++) {
if (arg.charAt(j) == c) {
counter++;
counted[j] = true;
}
}
res += counter + "" + c;
}
}
return res;
}
If you want to keep your original structure, I suggest using a StringBuilder so that you can delete characters that you have already seen. In case you delete a character, you have to adjust your indexes i and j.
public static String numLetters(String str){
StringBuilder s = new StringBuilder(s);
String end = new String();
int counter = 0;
char c,d;
for(int i=0; i<s.length();i++){
c = s.charAt(i);
for(int j=0; j<s.length();j++){
d = s.charAt(j);
if(c == d){
s.deleteCharAt(j);
if (i >= j) i--;
j--;
counter++;
}
}
end = end + counter+c;
counter = 0;
}
return end;
}
Try this:
int count = StringUtils.countMatches("a.b.c.d", ".");
// I have a program where I am supposed to count unique characters, only letters and numbers and don't count repeating numbers or letters. However, I have a problem finding out a way for the program not to count spaces and symbols such as "!" "#" "#" "$". So If i type in Hello! I only want the program to say "4", but it says "5" because it counts the exclamation point. Here is my code so far:
public static int countUniqueCharacters(String text1) {
int count = 0;
for (int i = 0; i < text1.length(); i++) {
if (text1.substring(0, i).contains(text1.charAt(i) + ""))
System.out.println();
else
count++;
}
return count;
}
In your else block add a condition that the count will be incremented only if the given character is a letter or a digit.
if (Character.isLetter(text1.charAt(i)) || Character.isDigit(text1.charAt(i))) {
count++;
}
In your example:
public static int countUniqueCharacters(String text1) {
int count = 0;
for (int i = 0; i < text1.length(); i++) {
if (text1.substring(0, i).contains(text1.charAt(i) + "")) {
System.out.println();
} else if (Character.isLetter(text1.charAt(i)) || Character.isDigit(text1.charAt(i))) {
count++;
}
}
return count;
}
here's a sample code written in C# try and understand it. It compares with ascii and adds in a list
string input = Console.ReadLine();//input
List<char> CountedCharacters = new List<char>();
for (int i = 0; i < input.Length; i++)
{ //checking for numerics //checking for alphabets uppercase //checking for alphabets lowercase
if ((input[i] >= 45 && input[i] <= 57) || (input[i] >= 65 && input[i] <= 90) || (input[i] >= 97 && input[i] <= 122))
{
bool AlreadyExists = false;
for (int j = 0; j < CountedCharacters.Count; j++)
{
////checking if already exists
if (CountedCharacters[j]==input[i])
{
AlreadyExists = true;
break;
}
}
////adding in list if doesnt exists
if (!AlreadyExists)
{
CountedCharacters.Add(input[i]);
}
}
}
for (int i = 0; i < CountedCharacters.Count; i++)
{
Console.WriteLine(CountedCharacters[i]);
}
Try this one using regex. You can add and remove the characters you need from the expression to count what you need.
public static int countUniqueCharacters(String text1) {
String newText = text1.replaceAll("[^A-Za-z0-9()\\[\\]]", "");
Set<Character> tempSet = new HashSet<>();
for (char item : newText.toCharArray()) {
tempSet.add(item);
}
return tempSet.size();
}
Given a polynomial with a single variable x, and the value of x as input, compute its value. Examples:
eval("-2x^3+10x-4x^2","3")=-60
eval("x^3+x^2+x","6")=258
Description of issue: In this code I break the string into a substring whenever a +/- is encountered and pass the substring to a function which evaluates single term like "-2x^3". So my code for input = "-2x^3+10x-4x^2" calculates till "-2x^3+10x" only and skips "-4x^2" part.
Can anyone please tell me whats wrong here?
public class EvalPolyX2 {
static String testcase1 = "-2x^3+10x-4x^2";
static String testcase2 = "3";
public static void main(String args[]){
EvalPolyX2 testInstance = new EvalPolyX2();
int result = testInstance.eval(testcase1,testcase2);
System.out.println("Result : "+result);
}
public int eval(String str,String valx){
int sum = 0;
String subStr = "";
if(str.charAt(0) == '-')
{
int len = str.length();
for (int i = 0; i < len; i++)
{
if(str.charAt(i) == '-' || str.charAt(i) == '+')
{
subStr = str.substring(0, i);
System.out.println("subStr="+subStr);
sum += evalSubPoly(subStr, valx);
str = str.substring(i);
len = str.length();
i = 0;
}
}
}
else if(str.charAt(0) != '-')
{
str = '+' + str;
int len = str.length();
for (int i = 0; i < len; i++)
{
if(str.charAt(i) == '-' || str.charAt(i) == '+')
{
subStr = str.substring(0, i);
System.out.println("subStr="+subStr);
sum += evalSubPoly(subStr, valx);
str = str.substring(i);
len = str.length();
i=0;
}
}
}
return sum;
}
public int evalSubPoly(String poly,String valx){
int len = poly.length();
String num = "";
String power = "";
int exp = 0, coeff = 0;
for(int i = 0; i < len; i++)
{
if(poly.charAt(i) == 'x')
{
num = poly.substring(0, i);
coeff = Integer.parseInt(num);
}
if(poly.charAt(i) == '^')
{
power = poly.substring(i+1, len);
exp = Integer.parseInt(power);
}
}
if(power.equals(""))
exp = 1;
System.out.println("coeff="+coeff);
int sum = 1;
int x = Integer.parseInt(valx);
for (int i = 0; i < exp; i++)
{
sum = sum*x;
}
System.out.println("sum="+sum);
sum = sum*coeff;
return sum;
}
}
What's wrong with using regex? You can split the polynomial into monomials, evaluate each, and add all of the results.
private static final Pattern monomial = Pattern
.compile("([+-])?(\\d+)?x(?:\\^(\\d+))?");
public static int eval(String str, String valx) {
Matcher m = monomial.matcher(str);
int x = Integer.parseInt(valx);
int total = 0;
while (m.find()) {
String mul = m.group(2);
int value = (mul == null) ? 1 : Integer.parseInt(m.group(2));
String pow = m.group(3);
value *= (pow == null) ? x : (int) Math.pow(x,
Integer.parseInt(pow));
if ("-".equals(m.group(1)))
value = -value;
total += value;
}
return total;
}
System.out.println(eval("-2x^3+10x-4x^2", "3"));
System.out.println(eval("x^3+x^2+x", "6"));
-60
258
This code replacement should help
if(str.charAt(i) == '-' || str.charAt(i) == '+' || i == (len - 1))
{
if(i == len - 1)
{
i++;
}
...
Though there could be better ways, but I only wanted to show a way out here.
The reason is you are looking for + or - as the delimiter.
But the last part of the expression will not end with either of these but just probably EOL
You need to account for the last term (the if-statement will only trigger when a - or + is found, which there isn't at the end).
One easy way to do this is to replace:
for (int i = 0; i < len; i++)
{
if (str.charAt(i) == '-' || str.charAt(i) == '+')
with:
// v one more iteration
for (int i = 0; i <= len; i++)
{
if (i == len || str.charAt(i) == '-' || str.charAt(i) == '+')
// \------/
// extra condition
The above simply goes on for one more iteration and, on that iteration, always goes into the if-statement, causing the last term to be processed.
You can also simplify
if (str.charAt(0) == '-')
{
// common code
}
else if (str.charAt(0) != '-')
{
str = '+' + str;
// common code
}
To:
if (str.charAt(0) != '-')
{
str = '+' + str;
}
// common code
There's also a bug with handling +. I get a NumberFormatException for this. One way to handle it is to ignore the + between the terms (and not adding a + to the start):
if (i != len && str.charAt(i) == '+')
str = str.substring(i+1);
else
str = str.substring(i);
And you might as well make your functions static and call them directly rather than declaring a new instance of your class.
Test.
The simple answer is that when you do this:
if(str.charAt(i) == '-' || str.charAt(i) == '+')
{
subStr = str.substring(0, i);
the effect is that you're setting subStr to text just before the - or +, and evaluating it. But since there's no - or + at the end of the string, there's no way this logic will evaluate the last term of the polynomial, since it only evaluates substrings that are right before a - or +.
P.S. That's just one problem I noticed. I don't know if the rest of the logic is correct.
When you parse the string, you look for +/- and only stop if you find them. This works for the first two terms, but when you get down to "-4x^2" the loop won't stop because there is no +/-. So in addition to the conditions you have, you need to add code so that when the end of the string is reached, what you have left is the last term. So what you want to have is this
if(str.charAt(0) == '-')
{
int len = str.length();
for (int i = 0; i < len; i++)
{
if(str.charAt(i) == '-' || str.charAt(i) == '+')
{
subStr = str.substring(0, i);
System.out.println("subStr="+subStr);
sum += evalSubPoly(subStr, valx);
str = str.substring(i+1);
len = str.length();
i = 0;
}
}
System.out.println("subStr="+str);
sum += evalSubPoly(str, valx);
}
else if(str.charAt(0) != '-')
{
str = '+' + str;
int len = str.length();
for (int i = 0; i < len; i++)
{
if(str.charAt(i) == '-' || str.charAt(i) == '+')
{
subStr = str.substring(0, i);
System.out.println("subStr="+subStr);
sum += evalSubPoly(subStr, valx);
str = str.substring(i+1);
len = str.length();
i=0;
}
}
System.out.println("subStr="+str);
sum += evalSubPoly(str, valx);
}
I will also throw out the disclaimer that there may be more errors, but this is the major one causing your problem.
EDIT: added change to else if statement and added change mentioned in my comment above
With regular expressions, you can get a more simple solution. And, do you want support for simple constants? Try the next:
public class EvalPolyX2 {
public static void main(String args[]) {
System.out.println("Result: " + eval("x^3+x^2+x", 6));
}
public static int eval(String eq, int val) {
int result = 0;
String mons[] = eq.split("(?=[+-])(?!\\B)");
for (String str : mons) {
str = str.replace("+", "");
if (str.contains("x")) {
double a = 1, b = 1;
String[] comps = str.split("x\\^?");
if (comps.length > 0) {
a = comps[0].isEmpty() ? 1 : Integer.parseInt(comps[0]);
}
if (comps.length > 1) {
b = Integer.parseInt(comps[1]);
}
result += a * Math.pow(val, b);
} else {
result += Integer.parseInt(str);
}
}
return result;
}
}