计算器、中文转数字

计算器

1.字符串转整数

string s = "458";

int n = 0;
for (int i = 0; i < s.size(); i++) {
    char c = s[i];
    n = 10 * n + (c - '0');
}
// n 现在就等于 458

2.处理加减法

我们拿字符串算式1-12+3为例,来说一个很简单的思路:

1、先给第一个数字加一个默认符号+,变成+1-12+3

2、把一个运算符和数字组合成一对儿,也就是三对儿+1-12+3,把它们转化成数字,然后放到一个栈中。

3、将栈中所有的数字求和,就是原算式的结果。

int calculate(string s) {
    stack<int> stk;
    // 记录算式中的数字
    int num = 0;
    // 记录 num 前的符号,初始化为 +
    char sign = '+';
    for (int i = 0; i < s.size(); i++) {
        char c = s[i];
        // 如果是数字,连续读取到 num
        if (isdigit(c)) 
            num = 10 * num + (c - '0');
        // 如果不是数字,就是遇到了下一个符号,
        // 之前的数字和符号就要存进栈中
        if (!isdigit(c) || i == s.size() - 1) {
            switch (sign) {
                case '+':
                    stk.push(num); break;
                case '-':
                    stk.push(-num); break;
            }
            // 更新符号为当前符号,数字清零
            sign = c;
            num = 0;
        }
    }
    // 将栈中所有结果求和就是答案
    int res = 0;
    while (!stk.empty()) {
        res += stk.top();
        stk.pop();
    }
    return res;
}

i就是从左到右扫描,signnum跟在它身后。s[i]遇到一个运算符时,情况是这样的

图片

所以说,此时要根据sign的 case 不同选择nums的正负号,存入栈中,然后更新sign并清零nums记录下一对儿符合和数字的组合。

另外注意,不只是遇到新的符号会触发入栈,当i走到了算式的尽头(i == s.size() - 1),也应该将前面的数字入栈,方便后续计算最终结果。

3. 处理乘除法

for (int i = 0; i < s.size(); i++) {
    char c = s[i];
    if (isdigit(c)) 
        num = 10 * num + (c - '0');

    if (!isdigit(c) || i == s.size() - 1) {
        switch (sign) {
            int pre;
            case '+':
                stk.push(num); break;
            case '-':
                stk.push(-num); break;
            // 只要拿出前一个数字做对应运算即可
            case '*':
                pre = stk.top();
                stk.pop();
                stk.push(pre * num);
                break;
            case '/':
                pre = stk.top();
                stk.pop();
                stk.push(pre / num);
                break;
        }
        // 更新符号为当前符号,数字清零
        sign = c;
        num = 0;
    }
}

乘除法优先于加减法体现在,乘除法可以和栈顶的数结合,而加减法只能把自己放入栈

图片

4.处理括号

那么,为什么说处理括号没有看起来那么难呢,因为括号具有递归性质。我们拿字符串3*(4-5/2)-6举例:

calculate(3*(4-5/2)-6)
= 3 * calculate(4-5/2) - 6
= 3 * 2 - 6
= 0

可以脑补一下,无论多少层括号嵌套,通过 calculate 函数递归调用自己,都可以将括号中的算式化简成一个数字。换句话说,括号包含的算式,我们直接视为一个数字就行了

现在的问题是,递归的开始条件和结束条件是什么?遇到(开始递归,遇到)结束递归:python版本

def calculate(s: str) -> int:

    def helper(s: List) -> int:
        stack = []
        sign = '+'
        num = 0

        while len(s) > 0:
            c = s.pop(0)
            if c.isdigit():
                num = 10 * num + int(c)
            # 遇到左括号开始递归计算 num
            if c == '(':
                num = helper(s)

            if (not c.isdigit() and c != ' ') or len(s) == 0:
                if sign == '+': ...
                elif sign == '-': ... 
                elif sign == '*': ...
                elif sign == '/': ...
                num = 0
                sign = c
            # 遇到右括号返回递归结果
            if c == ')': break
        return sum(stack)

    return helper(list(s))

Java版本:224. 基本计算器 

public int calculate(String s) {
    // Write your code here
    Deque<Character> q = new LinkedList<>();
    for (char c : s.toCharArray()) {
        q.offer(c);
    }
    return dfs_cal(q);
}
// 得到括号内的结果
public int dfs_cal(Deque<Character> q) {
    Stack<Integer> stack = new Stack<>();
    char op = '+';
    int num = 0;
    while (!q.isEmpty()) {
        char c = q.pollFirst();
        if (c == '(') {
            num = dfs_cal(q);
        }
        if (Character.isDigit(c)) {
            num = num * 10 + c - '0';
        }
        // 读取到最后一位时 要处理最后的逻辑
        if (q.isEmpty() || (!Character.isDigit(c) && c != ' ')) {
            if (op == '+') {
                stack.push(num);
            } else if (op == '-') {
                stack.push(-num);
            } else if (op == '*') {
                stack.push(stack.pop() * num);
            } else if (op == '/') {
                stack.push(stack.pop() / num);
            }
            op = c;
            num = 0;
        }
        // 右括号判断只能在最后 前面要处理计算逻辑
        if (c == ')') {
            break;
        }

    }
    int res = 0;
    for (int t : stack) {
        res += t;
    }
    return res;
}

中文转阿拉伯

//中文字转阿拉伯数字
public long zn_int(String num){
    if (num == null || num.length() == 0) return 0L;
    HashMap<Character, Long> numMap = new HashMap<>();
    numMap.put('零', 0L);numMap.put('一', 1L);numMap.put('二', 2L);
    numMap.put('三', 3L);numMap.put('四', 4L);numMap.put('五', 5L);
    numMap.put('六', 6L);numMap.put('七', 7L);numMap.put('八', 8L);
    numMap.put('九', 9L);numMap.put('十', 10L);numMap.put('廿', 20L);
    numMap.put('卅', 30L);numMap.put('百', 100L);numMap.put('千', 1000L);
    numMap.put('万', 10_000L);numMap.put('亿', 100_000_000L);

    // year 2 long 年份判断 一九四五 这种
    long tmpres = 0; 
    for (char c : num.toCharArray()) {
        long cur = numMap.get(c);
        if (cur >= 10) {
            tmpres = -1;
            break;
        }
        tmpres = tmpres*10 + cur;
    }
    if (tmpres > 0) return tmpres;

    LinkedList<Long> stack = new LinkedList<>();
    for (char c : num.toCharArray()) {
        long cur = numMap.get(c);
        if (stack.isEmpty() || stack.peek() > cur) {
            stack.push(cur);
        } else {
            long sum = 0;
            while (!stack.isEmpty() && stack.peek() < cur) {
                sum += stack.pop();
            }
            sum = (sum == 0 ? 1 : sum);
            stack.push(sum * cur);
        }
    }

    long res = 0;
    for (long t : stack){
        res += t;
    }
    return res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值