代码随想录算法训练营Day11|LC20 有效的括号&LC1047 删除字符串中的所有相邻重复项&LC150 逆波兰表达式(栈的应用)

本文讲述了如何通过栈和哈希表实现括号匹配算法,以及在字符串处理中删除相邻重复字符和评估逆波兰表达式的高效方法,重点在于代码实现的细节和技巧应用。
摘要由CSDN通过智能技术生成

一句话总结:栈的思想不难,难的是实现细节。

原题链接:

 原理很简单,遇到左括号入栈,遇到右括号就跟栈顶比较。如果组成了一对正确的括号则继续比较,否则返回false,直到遍历完整个字符串。写法细节上比较有说法:首先,用哈希表来存储每一对括号(题解写法是用右括号作为key,左括号作为value,实际上换一下也是可以的),可以很轻松的利用哈希表的get()方法来比较是否可以组成一对正确的括号;其次,事先计算字符串的长度是否为偶数可以剪枝;最后只需返回全部遍历完成以后栈是否为空即可。

class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        if (n % 2 == 1) return false;
        Map<Character, Character> pair = new HashMap<>();
        pair.put('}', '{');
        pair.put(']', '[');
        pair.put(')', '(');
        Deque<Character> stack = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            if (pair.containsKey(c)) {
                if (stack.isEmpty() || stack.peek() != pair.get(c)) return false;
                stack.pop();
            } else stack.push(c);
        }
        return stack.isEmpty();
    }
}

然后是执行更快速的写法:用一个与字符串等长的字符数组来作为栈,另外再设置一个指针p,遍历字符串的时候遇到左括号就将其放在数组中,指针向后移一位;遇到右括号则与指针的前一位比较是否配对,不是则返回false,是则将指针向前移动一位,到前面一个未配对左括号的后一位上。直到遍历完整个字符串,最后指针如果为0表示所有括号均可配对,正确。

class Solution {
    public boolean isValid(String s) {
        int p = 0, n = s.length();
        char[] opStack = new char[n];
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '[' || c == '{') {
                opStack[p++] = c;
            } else if (c == ')') {
                if (p > 0 && opStack[p - 1] == '(') p--;
                else return false;
            } else if (c == ']') {
                if (p > 0 && opStack[p - 1] == '[') p--;
                else return false;
            } else if (c == '}') {
                if (p > 0 && opStack[p - 1] == '{') p--;
                else return false;
            }
        }
        return p == 0;
    }
}

原题链接:1047 删除字符串中的所有相邻重复项

此题原理也不难。遍历字符串,如果此时遍历到的字符与前一个相等,就将其前一个字符删除;否则将该字符添加到字符串尾。难的是StringBuffer的操作。

class Solution {
    public String removeDuplicates(String s) {
        StringBuffer sb = new StringBuffer();
        for (char ch : s.toCharArray()) {
            if (sb.length() != 0 && sb.charAt(sb.length() - 1) == ch) {
                sb.deleteCharAt(sb.length() - 1);
            } else sb.append(ch);
        }
        return sb.toString();
    }
}

 另外还有一个利用快慢指针的解法,有点巧妙。先将字符串转换为字符数组,然后快指针每轮遍历往后移动一位,慢指针的操作非常关键,它在每轮遍历中先将其所指元素赋值为快指针所指元素,然后比较其是否与前一位字符相等,是则慢指针指向前一位,否则也向后移动一位。最后返回从0到慢指针所指位置的子串即可。

class Solution {
    public String removeDuplicates(String s) {
        char[] cs = s.toCharArray();
        int fast = 0, slow = 0;
        while (fast < cs.length) {
            cs[slow] = cs[fast];
            if (slow > 0 && cs[slow] == cs[slow - 1]) --slow;
            else ++slow;
            ++fast;
        }
        return new String(cs).substring(0, slow);
    }
}

原题链接:150 逆波兰表达式

此题思想不难,需要考虑的是equals方法的使用细节(是用"+".equals(token)而非token.equals("+")),以及最后针对除法的写法细节,需要用两个临时变量将栈顶两个元素依次出栈保存,再压入计算结果。另一个比较不容易想到的是Integer.valueOf()方法,这个方法可以将字符串转换为int类型的数字。

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> stack = new LinkedList<>();
        for (String token : tokens) {
            if ("+".equals(token)) stack.push(stack.pop() + stack.pop());
            else if ("-".equals(token)) stack.push(-stack.pop() + stack.pop());
            else if ("*".equals(token)) stack.push(stack.pop() * stack.pop());
            else if ("/".equals(token)) {
                int num1 = stack.pop(), num2 = stack.pop();
                stack.push(num2 / num1);
            } else stack.push(Integer.valueOf(token));
        }
        return stack.pop();
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值