计算器
224.基本计数器实现一个基本的计算器来计算一个简单的字符串表达式的值。字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
class Solution {
public int calculate(String s) {
int res=0,sign=1;
Stack<Integer> stack=new Stack<>();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(Character.isDigit(c)){
int cur=c-'0';
while(i<s.length()-1&&Character.isDigit(s.charAt(i+1))){
cur=cur*10+(s.charAt(++i)-'0');
}
res=res+sign*cur;
}else if(c=='+'){
sign=1;
}else if(c=='-'){
sign=-1;
}else if(c=='('){
stack.push(res);
res=0;
stack.push(sign);
sign=1;
}else if(c==')'){
res=stack.pop()*res+stack.pop();
}
}
return res;
}
}
227.基本计数器II实现一个基本的计算器来计算一个简单的字符串表达式的值。字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。
class Solution {
public int calculate(String s) {
Stack<Integer> stack=new Stack<>();
char sign='+';
int num=0;
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c>='0'){
num=num*10+(c-'0');
}
if(c<'0'&&c!=' '||i==s.length()-1){
if(sign=='+'){
stack.push(num);
}else if(sign=='-'){
stack.push(-num);
}else if(sign=='*'){
stack.push(stack.pop()*num);
}else if(sign=='/'){
stack.push(stack.pop()/num);
}
num=0;
sign=c;
}
}
int res=0;
while(!stack.isEmpty()){
res+=stack.pop();
}
return res;
}
}
基本计数器完整体(左括号 ( ,右括号 ),+, - ,*,/ 四种运算符和空格 )
class Solution {
public int calculate(String s) {
/*
将 减法、乘法、除法 转换为 加法
某个数 num, 如果前面的对应的运算符是 -,那么 将 -num 压入栈中
这样,我们只需在最后将栈的元素全部弹出,完成加法操作,即可得到最终结果
对于括号,它存在递归性质
即
3 * (2 + 4 * 3) + 2
= 3 * calculate(2 + 4 * 3) + 2
= 3 * 24 + 2
即我们可以将括号内的字符串当作一个运算式,再递归调用本函数,最终返回一个数值
*/
int[] i = new int[1];
return dfs(s, i);
}
private int dfs(String s, int[] i){
Deque<Integer> stack = new LinkedList<>();
//记录某个连续的数,比如 "42",那么我们首先 num = 4,然后遇到 2 ,num = num * 10 + 2 = 42
int num = 0;
char op = '+';
for(; i[0] < s.length(); i[0]++){
char ch = s.charAt(i[0]);
//遇到左括号,递归运算内部子式
if(ch == '('){
++i[0];
num = dfs(s, i);
}
if(Character.isDigit(ch)){
num = num * 10 + (ch - '0');
}
//不是数字,不是空格(运算符 或 '(' 或 ')' ) 或者 到了最后一个字符,那么根据前面记录的 op 操作符 将数字压栈,然后将新的运算符 ch 赋值给 op
if(!Character.isDigit(ch) && ch != ' ' || i[0] == s.length() - 1){
switch(op){
case '+':
stack.push(num); break;
case '-':
stack.push(-num); break;
case '*':
int pre = stack.pop();
stack.push(pre * num);
break;
case '/':
pre = stack.pop();
stack.push(pre / num);
break;
}
num = 0;
op = ch;
}
/*
遇到右括号,退出循环,然后计算结果, 返回上一层 dfs
这一步写在最后是因为,当 ch 为 右括号 时,那么我们需要先将前面已经得到的 num 压入栈中,再退出循环
*/
if(ch == ')'){
break;
}
}
int res = 0;
while(!stack.isEmpty()){
res += stack.pop();
}
return res;
}
}
波兰运算
150.逆波兰表达式求值有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack=new Stack<>();
for(String s:tokens){
if(s.equals("+")){
int temp=stack.pop()+stack.pop();
stack.push(temp);
}else if(s.equals("-")){
int temp=-stack.pop()+stack.pop();
stack.push(temp);
}else if(s.equals("*")){
int temp=stack.pop()*stack.pop();
stack.push(temp);
}else if(s.equals("/")){
int fenmu=stack.pop();
int fenzi=stack.pop();
stack.push(fenzi/fenmu);
}else{
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
添加运算符
282.给表达式添加运算符给定一个仅包含数字 0-9 的字符串和一个目标值,在数字之间添加二元运算符(不是一元)+、- 或 * ,返回所有能够得到目标值的表达式。
class Solution {
List<String> re=new ArrayList<>();
public List<String> addOperators(String num, int target) {
if(num.length()==0) return new ArrayList<>();
dfs(num,target,new ArrayList<>(),0,0,0,0);
return re;
}
public void dfs(String num,int target,List<String> temp,long preNum,long curNum,long value,int index){
if(index==num.length()){
if(value==target&&curNum==0){
StringBuffer sb=new StringBuffer();
temp.subList(1,temp.size()).forEach(v->sb.append(v));
re.add(sb.toString());
}
return;
}
curNum=curNum*10+(num.charAt(index)-'0');
String curNum_str=Long.toString(curNum);
if(curNum>0){
dfs(num,target,temp,preNum,curNum,value,index+1);
}
temp.add("+");
temp.add(curNum_str);
dfs(num,target,temp,curNum,0,value+curNum,index+1);
temp.remove(temp.size()-1);
temp.remove(temp.size()-1);
if(temp.size()>0){
temp.add("-");
temp.add(curNum_str);
dfs(num,target,temp,-curNum,0,value-curNum,index+1);
temp.remove(temp.size()-1);
temp.remove(temp.size()-1);
temp.add("*");
temp.add(curNum_str);
dfs(num,target,temp,preNum*curNum,0,value-preNum+curNum*preNum,index+1);
temp.remove(temp.size()-1);
temp.remove(temp.size()-1);
}
}
}
494.目标和给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
//0-1背包法
class Solution {
public int findTargetSumWays(int[] nums, int S) {
if(nums.length==0) return 0;
int sum=0;
for(int i:nums) sum+=i;
if(sum<S||(sum+S)%2!=0) return 0;
int V=(sum+S)/2;
int[] dp=new int[V+1];
dp[0]=1;
for(int num:nums){
int i=V;
while(i>=num){
dp[i]+=dp[i-num];
i--;
}
}
return dp[V];
}
}
241.为运算表达式设计优先级给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
class Solution {
//添加一个 map
HashMap<String,List<Integer>> map = new HashMap<>();
public List<Integer> diffWaysToCompute(String input) {
if (input.length() == 0) {
return new ArrayList<>();
}
//如果已经有当前解了,直接返回
if(map.containsKey(input)){
return map.get(input);
}
List<Integer> result = new ArrayList<>();
int num = 0;
int index = 0;
while (index < input.length() && !isOperation(input.charAt(index))) {
num = num * 10 + input.charAt(index) - '0';
index++;
}
if (index == input.length()) {
result.add(num);
//存到 map
map.put(input, result);
return result;
}
for (int i = 0; i < input.length(); i++) {
if (isOperation(input.charAt(i))) {
List<Integer> result1 = diffWaysToCompute(input.substring(0, i));
List<Integer> result2 = diffWaysToCompute(input.substring(i + 1));
for (int j = 0; j < result1.size(); j++) {
for (int k = 0; k < result2.size(); k++) {
char op = input.charAt(i);
result.add(caculate(result1.get(j), op, result2.get(k)));
}
}
}
}
//存到 map
map.put(input, result);
return result;
}
private int caculate(int num1, char c, int num2) {
switch (c) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
}
return -1;
}
private boolean isOperation(char c) {
return c == '+' || c == '-' || c == '*';
}
}