From 6f46fe956145953597cbde4c05ccbf723ce3090d Mon Sep 17 00:00:00 2001 From: ardallie Date: Wed, 18 Aug 2021 00:18:55 +0100 Subject: [PATCH 1/3] Calculator --- src/hard/Calculator.java | 259 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 src/hard/Calculator.java diff --git a/src/hard/Calculator.java b/src/hard/Calculator.java new file mode 100644 index 0000000..35831de --- /dev/null +++ b/src/hard/Calculator.java @@ -0,0 +1,259 @@ +package hard; + +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Have the function Calculator(str) take the str parameter being passed + * and evaluate the mathematical expression within in. + * For example, if str were "2+(3-1)*3" the output should be 8. + * Another example: if str were "(2-0)(6/2)" the output should be 6. + * There can be parenthesis within the string, so you must evaluate it + * properly according to the rules of arithmetic. + * The string will contain the operators: +, -, /, *, (, and ). + * If you have a string like this: #/#*# or #+#(#)/#, + * then evaluate from left to right. So divide then multiply, + * and for the second one multiply, divide, then add. + * The evaluations will be such that there will not be any decimal operations, + * so you do not need to account for rounding and whatnot. + */ +class Calculator { + + // evaluate the Postfix expression + private static final Stack stack = new Stack<>(); + + /** + * Cleaning, parsing and splitting the input string into the array of tokens + * 1. convert to lowercase + * 2. replace (a)(b) with (a) * (b) + * 3. replace a(b) with a * (b) + * 4. split two bundled characters (but only when the second character is not a digit) + * 5. split bundled command/operator and a digit. Excl. minus to keep negative numbers intact. + * 6. remove multiple spaces + * 7. trim (remove leading and trailing spaces) + * 8. split to array of strings + * + * @param input input string + * @return array of strings with parsed operators and operands + */ + private static String[] parseConsoleInput(String input) { + return input + .toLowerCase() + .replaceAll("(\\)\\()", ") * (") + .replaceAll("([0-9])(?=[(])", "$1 *") + .replaceAll("([\\p{P}\\p{S}a-z0-9])(?=[\\p{P}\\p{S}a-z])", "$1 ") + .replaceAll("([^0-9])(?=[0-9])", "$1 ") + .replaceAll(" +", " ") + .trim() + .split(" "); + } + + /** + * Prints out a message to the console if the user input is invalid. + * + * @param op single element of the input string + */ + private static void printInputError(String op) { + System.out.println("Unrecognised operator or operand: \"" + op + "\"."); + } + + /** + * Reduces two operands to a single result + * by performing an arithmetical operation. + * + * @param a operand A + * @param b operand B + * @param operator denotes operation type (addition, substraction, division etc.) + * @return result of the arithmetical operation + * @throws ArithmeticException if divisor is 0 + */ + public static long reduceOperands(long a, long b, String operator) { + switch (operator) { + case "+": + return a + b; + case "-": + return a - b; + case "*": + return a * b; + case "/": + if (b == 0) { + System.out.println("Divide by 0."); + throw new ArithmeticException(); + } + return a / b; + default: + return 0; + } + } + + /** + * Checks if the token is an operand (0-9). + * + * @param op a single token from the input string + * @return true if the token is an operand, false if not + */ + private static boolean isOperand(String op) { + Pattern pattern = Pattern.compile("^[\\d]|^-[\\d]"); + Matcher matcher = pattern.matcher(op); + return matcher.find(); + } + + /** + * Checks if the token is an operator + - * / : ^ ( ) etc. + * + * @param op a single token from the input string + * @return true if the token is an operator, false if not + */ + private static boolean isOperator(String op) { + Pattern pattern = Pattern.compile("^[+\\-*/^%]"); + Matcher matcher = pattern.matcher(op); + return matcher.find(); + } + + /** + * Converts the Infix expression to Postfix. + * + * @param tokens expression tokens that are already parsed and split + */ + private static String[] convertToPostfix(String[] tokens) { + Stack infStack = new Stack<>(); + String terminating = "#"; + Dictionary precedence = new Hashtable<>() { + { + put(terminating, 0); + put("(", 0); + put(")", 0); + put("+", 1); + put("-", 1); + put("*", 2); + put("/", 2); + } + }; + ArrayList output = new ArrayList<>(); + infStack.push(terminating); + for (String token : tokens) { + // token is an operand, add to output and move on + if (isOperand(token)) { + output.add(token); + continue; + } + // left parenthesis, push it to stack and move on + if (token.equals("(")) { + infStack.push(token); + continue; + } + // right parenthesis, keep popping until the left parenthesis is found + if (token.equals(")")) { + while (true) { + String op = infStack.pop(); + if (op.equals("(")) { + break; + } else { + output.add(op); + } + } + continue; + } + // token is an operator + if (isOperator(token)) { + int cmp1 = precedence.get(token); + while (true) { + int cmp2 = precedence.get(infStack.peek()); + // operand has higher precedence than item on the top of stack + if (cmp1 > cmp2) { + infStack.push(token); + break; + } else { + output.add(infStack.pop()); + } + } + } + } + // pop the remaining items until the terminating symbol is reached (complete) + while (!infStack.empty() && !infStack.peek().equals(terminating)) { + output.add(infStack.pop()); + } + return output.toArray(new String[0]); + } + + /** + * Takes two operands from stack and perform the operation with a provider operator. + * + * @param operator denotes operation type (addition, substraction, division etc.) + * @return result of the evaluation + */ + private static String performArithOperation(String operator) { + if (stack.size() >= 2) { + // Safe to evaluate + String elementB = stack.pop(); + String elementA = stack.pop(); + long opB = Long.parseLong(elementB); + long opA = Long.parseLong(elementA); + long result = reduceOperands(opA, opB, operator); + return Long.toString(result); + } else { + // Stack underflow since at least one element is null + return null; + } + } + + /** + * Computes the entire expression in Reverse Polish Notation. + * + * @param tokens expression tokens that are already parsed and split to Array of Strings + */ + private static Long evaluateExpression(String[] tokens) { + for (String token : tokens) { + // token is an operand, push it to stack and move on + if (isOperand(token)) { + stack.push(token); + continue; + } + // token is an operator, evaluate + if (isOperator(token)) { + String result = performArithOperation(token); + if (result != null) { + stack.push(result); + } + continue; + } + // token is illegal + printInputError(token); + } + // all tokens have been processed + if (stack.isEmpty()) { + return null; + } + return Long.parseLong(stack.peek()); + } + + + /** + * Calculate function. + * + * @param expression input to evaluate + * @return result of evaluation + */ + public static String calculate(String expression) { + String[] tokens = parseConsoleInput(expression); + String[] postfix = convertToPostfix(tokens); + Long result = evaluateExpression(postfix); + return result == null ? "" : result.toString(); + } + + /** + * Entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + String expression = "8-7*(12+100/2)*9-2"; + String result = calculate(expression); + System.out.println(result); + } + +} From 282e696f4c5965c10bdf31b1280fa41e3180f2bf Mon Sep 17 00:00:00 2001 From: ardallie Date: Wed, 18 Aug 2021 00:24:41 +0100 Subject: [PATCH 2/3] Reverse Polish Notation --- src/hard/ReversePolishNotation.java | 171 ++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/hard/ReversePolishNotation.java diff --git a/src/hard/ReversePolishNotation.java b/src/hard/ReversePolishNotation.java new file mode 100644 index 0000000..9d25e16 --- /dev/null +++ b/src/hard/ReversePolishNotation.java @@ -0,0 +1,171 @@ +package hard; + +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Have the function ReversePolishNotation(str) read str which will be an arithmetic expression + * composed of only integers and the operators: +,-,* and / + * and the input expression will be in postfix notation (Reverse Polish notation), + * an example: (1 + 2) * 3 would be 1 2 + 3 * in postfix notation. + * Your program should determine the answer for the given postfix expression. + * For example: if str is 2 12 + 7 / then your program should output 2. + */ +class ReversePolishNotation { + + private static final Stack stack = new Stack<>(); + + /** + * Cleaning, parsing and splitting the input string into the array of tokens. + * 1. convert to lowercase + * 2. remove multiple spaces + * 3. split two bundled characters (but only when the second character is not a digit) + * 4. split bundled command/operator and a digit. Excl. minus to keep negative numbers intact. + * 5. trim (remove leading and trailing spaces) + * 6. split to array of strings + * + * @param input input string + * @return String array with parsed operators and operands + */ + private static String[] parseConsoleInput(String input) { + return input + .toLowerCase() + .replaceAll(" +", " ") + .replaceAll("([\\p{P}\\p{S}a-z0-9])(?=[\\p{P}\\p{S}a-z])", "$1 ") + .replaceAll("([^- 0-9])(?=[0-9])", "$1 ") + .trim() + .split(" "); + } + + /** + * Prints out a message to the console if the user input is invalid. + * + * @param op single element of the input string + */ + private static void printInputError(String op) { + System.out.println("Unrecognised operator or operand: \"" + op + "\"."); + } + + /** + * Reduces two operands to a single result + * by performing an arithmetical operation. + * + * @param a operand A + * @param b operand B + * @param operator denotes operation type (addition, substraction, division etc.) + * @return result of the arithmetical operation + * @throws ArithmeticException if divisor is 0 + */ + public static long reduceOperands(long a, long b, String operator) { + switch (operator) { + case "+": + return a + b; + case "-": + return a - b; + case "*": + return a * b; + case "/": + if (b == 0) { + System.out.println("Divide by 0."); + throw new ArithmeticException(); + } + return a / b; + default: + return 0; + } + } + + /** + * Checks if the token is an operand (0-9). + * + * @param op a single token from the input string + * @return true if the token is an operand, false if not + */ + private static boolean isOperand(String op) { + Pattern pattern = Pattern.compile("^[\\d]|^-[\\d]"); + Matcher matcher = pattern.matcher(op); + return matcher.find(); + } + + /** + * Checks if the token is an operator + - * / : ^ ( ) etc. + * + * @param op a single token from the input string + * @return true if the token is an operator, false if not + */ + private static boolean isOperator(String op) { + Pattern pattern = Pattern.compile("^[+\\-*/^%]"); + Matcher matcher = pattern.matcher(op); + return matcher.find(); + } + + /** + * Takes two operands from stack and perform the operation with a provider operator. + * + * @param operator denotes operation type (addition, substraction, division etc.) + * @return result of the evaluation + */ + private static String performArithOperation(String operator) { + if (stack.size() >= 2) { + // Safe to evaluate + String elementB = stack.pop(); + String elementA = stack.pop(); + long opB = Long.parseLong(elementB); + long opA = Long.parseLong(elementA); + long result = reduceOperands(opA, opB, operator); + return Long.toString(result); + } else { + // Stack underflow since at least one element is null + return null; + } + } + + /** + * Computes the entire expression in Reverse Polish Notation. + * + * @param tokens expression tokens that are already parsed and split to Array of Strings + */ + private static Long evaluateExpression(String[] tokens) { + for (String token : tokens) { + // token is an operand, push it to stack and move on + if (isOperand(token)) { + stack.push(token); + continue; + } + // token is an operator, evaluate + if (isOperator(token)) { + String result = performArithOperation(token); + if (result != null) { + stack.push(result); + } + continue; + } + // token is illegal + printInputError(token); + } + // all tokens have been processed + if (stack.isEmpty()) { + return null; + } + return Long.parseLong(stack.peek()); + } + + public static String reversePolishNotation(String expression) { + String[] tokens = parseConsoleInput(expression); + Long result = evaluateExpression(tokens); + return result == null ? "" : result.toString(); + } + + /** + * Entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + String expression = "1 1 + 1 + 1 +"; + String result = reversePolishNotation(expression); + System.out.println(result); + } + +} From fe1c8e2439efd34124fcb30091260d4aec8788a7 Mon Sep 17 00:00:00 2001 From: ardallie Date: Wed, 18 Aug 2021 00:34:19 +0100 Subject: [PATCH 3/3] Roman Numeral Reduction --- src/hard/RomanNumReduction.java | 91 +++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/hard/RomanNumReduction.java diff --git a/src/hard/RomanNumReduction.java b/src/hard/RomanNumReduction.java new file mode 100644 index 0000000..389ebef --- /dev/null +++ b/src/hard/RomanNumReduction.java @@ -0,0 +1,91 @@ +package hard; + +import java.util.HashMap; + +/** + * Have the function RomanNumeralReduction(str) read str + * which will be a string of roman numerals in decreasing order. + * The numerals being used are: I for 1, V for 5, X for 10, + * L for 50, C for 100, D for 500 and M for 1000. + * Your program should return the same number given + * by str using a smaller set of roman numerals. + * For example: if str is "LLLXXXVVVV" this is 200, so your program should return CC + * because this is the shortest way to write 200 using the roman numeral system given above. + * If a string is given in its shortest form, just return that same string. + */ +public class RomanNumReduction { + + private static final HashMap romans = new HashMap<>() { + { + put("M", 1000); + put("D", 500); + put("C", 100); + put("L", 50); + put("X", 10); + put("V", 5); + put("I", 1); + } + }; + + private static final String[] orderedRomans = new String[]{"M", "D", "C", "L", "X", "V", "I"}; + + /** + * Calculate the sum for an expression. + * + * @param exp expression + * @return a sum + */ + public static int sumRomans(String exp) { + int result = 0; + String[] tokens = exp.toUpperCase().split(""); + for (String token : tokens) { + result += romans.get(token); + } + return result; + } + + /** + * Reduce Roman numerals. + * + * @param sum a number + * @return a string of Roman numerals + */ + public static String reduceRomans(int sum) { + StringBuilder output = new StringBuilder(); + int remainder = sum; + for (String numeral : orderedRomans) { + Integer val = romans.get(numeral); + while (remainder / val >= 0 && remainder - val >= 0) { + output.append(numeral); + remainder -= val; + } + } + return output.toString(); + } + + /** + * Roman Numeral Reduction function. + * + * @param str input string + * @return result + */ + public static String romanNumeralReduction(String str) { + int sum = sumRomans(str); + return reduceRomans(sum); + } + + /** + * Entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + String result1 = romanNumeralReduction("XXXVVIIIIIIIIII"); + System.out.println(result1); + String result2 = romanNumeralReduction("VVV"); + System.out.println(result2); + String result3 = romanNumeralReduction("CCCCCIIIII"); + System.out.println(result3); + } + +} 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