Skip to content

Commit 282e696

Browse files
committed
Reverse Polish Notation
1 parent 6f46fe9 commit 282e696

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

src/hard/ReversePolishNotation.java

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package hard;
2+
3+
import java.util.Stack;
4+
import java.util.regex.Matcher;
5+
import java.util.regex.Pattern;
6+
7+
/**
8+
* Have the function ReversePolishNotation(str) read str which will be an arithmetic expression
9+
* composed of only integers and the operators: +,-,* and /
10+
* and the input expression will be in postfix notation (Reverse Polish notation),
11+
* an example: (1 + 2) * 3 would be 1 2 + 3 * in postfix notation.
12+
* Your program should determine the answer for the given postfix expression.
13+
* For example: if str is 2 12 + 7 / then your program should output 2.
14+
*/
15+
class ReversePolishNotation {
16+
17+
private static final Stack<String> stack = new Stack<>();
18+
19+
/**
20+
* Cleaning, parsing and splitting the input string into the array of tokens.
21+
* 1. convert to lowercase
22+
* 2. remove multiple spaces
23+
* 3. split two bundled characters (but only when the second character is not a digit)
24+
* 4. split bundled command/operator and a digit. Excl. minus to keep negative numbers intact.
25+
* 5. trim (remove leading and trailing spaces)
26+
* 6. split to array of strings
27+
*
28+
* @param input input string
29+
* @return String array with parsed operators and operands
30+
*/
31+
private static String[] parseConsoleInput(String input) {
32+
return input
33+
.toLowerCase()
34+
.replaceAll(" +", " ")
35+
.replaceAll("([\\p{P}\\p{S}a-z0-9])(?=[\\p{P}\\p{S}a-z])", "$1 ")
36+
.replaceAll("([^- 0-9])(?=[0-9])", "$1 ")
37+
.trim()
38+
.split(" ");
39+
}
40+
41+
/**
42+
* Prints out a message to the console if the user input is invalid.
43+
*
44+
* @param op single element of the input string
45+
*/
46+
private static void printInputError(String op) {
47+
System.out.println("Unrecognised operator or operand: \"" + op + "\".");
48+
}
49+
50+
/**
51+
* Reduces two operands to a single result
52+
* by performing an arithmetical operation.
53+
*
54+
* @param a operand A
55+
* @param b operand B
56+
* @param operator denotes operation type (addition, substraction, division etc.)
57+
* @return result of the arithmetical operation
58+
* @throws ArithmeticException if divisor is 0
59+
*/
60+
public static long reduceOperands(long a, long b, String operator) {
61+
switch (operator) {
62+
case "+":
63+
return a + b;
64+
case "-":
65+
return a - b;
66+
case "*":
67+
return a * b;
68+
case "/":
69+
if (b == 0) {
70+
System.out.println("Divide by 0.");
71+
throw new ArithmeticException();
72+
}
73+
return a / b;
74+
default:
75+
return 0;
76+
}
77+
}
78+
79+
/**
80+
* Checks if the token is an operand (0-9).
81+
*
82+
* @param op a single token from the input string
83+
* @return true if the token is an operand, false if not
84+
*/
85+
private static boolean isOperand(String op) {
86+
Pattern pattern = Pattern.compile("^[\\d]|^-[\\d]");
87+
Matcher matcher = pattern.matcher(op);
88+
return matcher.find();
89+
}
90+
91+
/**
92+
* Checks if the token is an operator + - * / : ^ ( ) etc.
93+
*
94+
* @param op a single token from the input string
95+
* @return true if the token is an operator, false if not
96+
*/
97+
private static boolean isOperator(String op) {
98+
Pattern pattern = Pattern.compile("^[+\\-*/^%]");
99+
Matcher matcher = pattern.matcher(op);
100+
return matcher.find();
101+
}
102+
103+
/**
104+
* Takes two operands from stack and perform the operation with a provider operator.
105+
*
106+
* @param operator denotes operation type (addition, substraction, division etc.)
107+
* @return result of the evaluation
108+
*/
109+
private static String performArithOperation(String operator) {
110+
if (stack.size() >= 2) {
111+
// Safe to evaluate
112+
String elementB = stack.pop();
113+
String elementA = stack.pop();
114+
long opB = Long.parseLong(elementB);
115+
long opA = Long.parseLong(elementA);
116+
long result = reduceOperands(opA, opB, operator);
117+
return Long.toString(result);
118+
} else {
119+
// Stack underflow since at least one element is null
120+
return null;
121+
}
122+
}
123+
124+
/**
125+
* Computes the entire expression in Reverse Polish Notation.
126+
*
127+
* @param tokens expression tokens that are already parsed and split to Array of Strings
128+
*/
129+
private static Long evaluateExpression(String[] tokens) {
130+
for (String token : tokens) {
131+
// token is an operand, push it to stack and move on
132+
if (isOperand(token)) {
133+
stack.push(token);
134+
continue;
135+
}
136+
// token is an operator, evaluate
137+
if (isOperator(token)) {
138+
String result = performArithOperation(token);
139+
if (result != null) {
140+
stack.push(result);
141+
}
142+
continue;
143+
}
144+
// token is illegal
145+
printInputError(token);
146+
}
147+
// all tokens have been processed
148+
if (stack.isEmpty()) {
149+
return null;
150+
}
151+
return Long.parseLong(stack.peek());
152+
}
153+
154+
public static String reversePolishNotation(String expression) {
155+
String[] tokens = parseConsoleInput(expression);
156+
Long result = evaluateExpression(tokens);
157+
return result == null ? "" : result.toString();
158+
}
159+
160+
/**
161+
* Entry point.
162+
*
163+
* @param args command line arguments
164+
*/
165+
public static void main(String[] args) {
166+
String expression = "1 1 + 1 + 1 +";
167+
String result = reversePolishNotation(expression);
168+
System.out.println(result);
169+
}
170+
171+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy