算法訓練 表達式計算
時間限制:1.0s 內存限制:256.0MB
問題描述
輸入一個只包含加減乖除和括號的合法表達式,求表達式的值。其中除表示整除。
輸入格式
輸入一行,包含一個表達式。
輸出格式
輸出這個表達式的值。
樣例輸入
1-2+3*(4-5)
樣例輸出
-4
數據規模和約定
表達式長度不超過100,表達式運算合法且運算過程都在int內進行。
題目解析:
運算優先級: 括號 → 乘除 → 加減
例如 1-2+3*(4-5)
(1)計算(4-5),表達式變為 1-2+3*-1
(2)計算 3*-1,表達式變為 1-2+-3
(3)計算 1-2,表達式變為 -1+-3
(4)計算 -1+-3,表達式變為 -4
(5)結果 -4
根據這一規律,我們首先在輸入的表達式兩端加上括號,使程序變為重復去計算括號中的子表達式。計算規則如同上例。
示例代碼:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 public class Main { 6 public static void main(String[] args) throws IOException { 7 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 8 StringBuilder expression = new StringBuilder("("+br.readLine()+")"); //表達式,在輸入的表達式兩邊加上括號 9 StringBuilder temp = new StringBuilder(); //存放臨時表達式,即每次存放的都是任意一個括號中的子表達式 10 while(true){ 11 int frontBrackets = expression.lastIndexOf("("); //從表達式后邊開始搜索,找到最后一個"(" 12 int backBrackets = expression.indexOf(")", frontBrackets); //從最后一個"("的位置開始往后搜索,找到與之對應的")" 13 14 if(frontBrackets == -1) break; //若再無表達式需要計算,即expression只有一個整數時,跳出循環 15 16 temp.append(expression.substring(frontBrackets + 1 , backBrackets)); //將此括號中的表達式存入temp 17 expression.delete(frontBrackets, backBrackets + 1); //在原始表達式中將括號連同其中的表達式刪除 18 19 for(int i = 0; i < temp.length(); i++){ //從子表達式中找出運算符,根據運算原則,先乘除后加減 20 if(temp.charAt(i) == '*'){ //若找到 "*" ,調用calculation進行運算 21 calculation(temp , '*' , i); 22 i = 0; //運算完后,i清零,方便下一次從開始位置繼續尋找乘除運算符 23 } 24 25 if(temp.charAt(i) == '/'){ 26 calculation(temp , '/' , i); 27 i = 0; 28 } 29 } 30 31 for(int i = 0; i < temp.length(); i++){ //找完乘除運算符后,開始找加減雲算符 32 if(temp.charAt(i) == '+'){ 33 calculation(temp , '+' , i); 34 i = 0; 35 } 36 37 if(temp.charAt(i) == '-'){ 38 calculation(temp , '-' , i); 39 i = 0; 40 } 41 } 42 43 expression.insert(frontBrackets, temp); //運算完后,將結果插入在剛才刪除的括號位置,構成新的表達式,繼續循環計算 44 temp.delete(0, temp.length()); //將temp清空,方便下一個表達式計算 45 46 } 47 48 System.out.println(expression); //輸出結果 49 } 50 51 /** 52 * 計算表達式 53 * @param src 表達式 54 * @param op 操作符 55 * @param location 操作符在表達式中的位置 56 */ 57 private static void calculation(StringBuilder src, char op, int location) { 58 int x = 0; //操作數1 59 int y = 0; //操作數2 60 int sum = 0;// sum = x (op) y 61 62 String check = "0123456789+-"; //檢測運算符兩邊的內容是否為其中數組或者正數或負數 63 StringBuilder temp = new StringBuilder(); //存放運算符兩邊的字符 64 65 if(location == 0) return; //若遇到子表示其中只有加減運算符這種情況,且遇到的第一個運算符其實是想表示一個正數或者負數的符號,則函數返回,繼續尋找下一個運算符 66 67 int k = 0; //搜索操作符左右兩邊的數 68 for(k = location - 1; k >= 0 && check.contains(src.charAt(k) + ""); k--){ //從運算符左邊一個位置開始往前搜索,找到第一個操作數 69 try{ 70 //若數字前邊有兩個運算符,第一個是為了與前邊的數相連,第二個是為了表示這個數的正負,則跳出循環,執行后面的語句 71 //比如: 5+(7+-5*+10),搜索到5前邊時,先搜索到"-",發現前邊還有一個"+",此時temp中沒有運算符,則繼續執行,當搜索到"+"時,發現前邊沒有運算符了,就跳出循環 72 if((src.charAt(k) == '+' || src.charAt(k) == '-') && (src.charAt(k-1) != '+' || src.charAt(k-1) != '-' )) 73 break; 74 if(temp.charAt(0) == '+' || temp.charAt(0) == '-') 75 break; 76 77 }catch(Exception e){ 78 // e.printStackTrace(); //不輸出異常,滿足題目輸出要求 79 } 80 81 temp.insert(0, src.charAt(k)); //每次都是從temp的開始位置插入內容,保證逆向搜索的內容能按照正常的順序存入temp 82 src.deleteCharAt(k); //刪除運算符前邊的那個數字,若有正負號,也一並刪除 83 } 84 85 x = Integer.parseInt(temp.toString()); //將搜索到的此數存入x 86 temp.delete(0, temp.length()); //將temp清空 87 88 for(k = k + 2; k < src.length() && check.contains(src.charAt(k) + ""); ){ //從運算符右邊一個位置開始往后搜索,找到第二個操作數,加2是因為上邊的循環語句在結束時自減了一次 89 90 if((src.charAt(k) == '+' || src.charAt(k) == '-') && (temp.length() != 0)) 91 break; 92 93 temp.append(src.charAt(k)); 94 src.deleteCharAt(k); 95 } 96 97 y = Integer.parseInt(temp.toString()); 98 temp.delete(0, temp.length()); 99 100 switch(op){ 101 case '+': 102 sum = x + y; 103 src.deleteCharAt(k-1); //刪除運算符 104 src.insert(k-1, sum + ""); //將結果存入src的操作符位置(此時操作符兩邊的數已經從src中刪除,所以插入此位置相當於用結果代替子表達式,方便下一次運算) 105 break; 106 107 case '-': 108 sum = x - y; 109 src.deleteCharAt(k-1); 110 src.insert(k-1, sum + ""); 111 break; 112 113 case '*': 114 sum = x * y; 115 src.deleteCharAt(k-1); 116 src.insert(k-1, sum + ""); 117 break; 118 119 case '/': 120 sum = x / y; 121 src.deleteCharAt(k-1); 122 src.insert(k-1, sum + ""); 123 break; 124 125 default: 126 break; 127 } 128 } 129 }
