代码随想录算法训练营第十一天|20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值

        不知不觉就第十一天了,加油!!!

20. 有效的括号

题目链接:20. 有效的括号

        我用的是Java自带Stack(栈)实现的匹配(我的上一篇文章总结了Java自带的栈(Stack)、队列(Queue)、双端队列(Deque))。这里有个小细节:当遇到朝右的括号时,加入栈中的是朝左的括号,即,他的匹配项,或者互补项。这与“两数之和”寻找两数时,使用哈希法有异曲同工之妙!“两数之和”中(第六天打卡文章“两数之和”中有详解),是在哈希表里查找是否存在目标值的互补项,这种存入互补项,之后直接对比互补项是否相等的思路,还是非常妙的。

代码:

public boolean isValid(String s) {
       Stack<Character> check = new Stack<>();
        char[] ch = s.toCharArray();
        for(int i = 0; i < ch.length; i++) {
            switch(ch[i]) {				// 加入它的互补项(朝左的括号),等等匹配时,只需要判断是否相等即可
                case '(':
                    check.add(')');
                    break;
                case '{':
                    check.add('}');
                    break;
                case '[':
                    check.add(']');
                    break;
            }
            if(ch[i] == ')' || ch[i] == '}' || ch[i] == ']' ) {// 遇到朝左的括号,开始匹配
                if(check.isEmpty()) {	// 遇到左括号,但是栈为空,则返回false
                    return false;
                }else {					// 不为空,那么开始配对
                    // 经过刚才的入栈,栈里是 朝左的 括号,只需判断是否相等即可
                    if(check.peek() != ch[i]) {
                        return false;	// 遇到不匹配的括号
                    }else {
                        check.pop();	// 相等则出栈
                    }
                }
            }
        }
        // 判断栈是否为空,不为空,那么说明还有没有匹配的左括号,返回false
        if(!check.isEmpty()) {
            return false;
        }else {// 为空,说明全部配对~
            return true;	
        }
        // 其实可以直接return check.isEmpty();
    }

哈希法的尝试:        

        当然,我也尝试了用哈希法(有关哈希法常用的三个哈希表:set、map,第六天打卡文章中也有总结)来解决,下面是思路:

 哈希法代码如下:

/**
		 * 	哈希法
		 * 	用HashMap作为哈希表,key:(朝右括号对应的)朝左的括号
		 * 					  value:(需要的)朝左的括号数
		 * 	根据我设计的这个key-value组合,即,当遇到一个朝右括号,就设置一个朝左括号(key),并设置朝左括号数(value)加1,
		 * 	后续遇到一次朝左的括号(key),就让朝左括号数(value)减1
         *  当遇到value小于0,说明“左括号必须以正确的顺序闭合”不满足了
		 * 	当第一次遍历字符串结束之后,再遍历一次map,看看是否有value值不为0的,有则说明无效
		 */
public boolean isValid(String s) {
        // 哈希法:
        Map<Character,Integer> checkMap = new HashMap<>();
        char[] ch = s.toCharArray();
        for(char c : ch){
            // 当遇到一个朝右括号,就设置一个朝左括号(key),并设置朝左括号数(value)加1
            if(c == '(') {
                checkMap.put(')', checkMap.getOrDefault(')', 0) + 1);
            }
            else if(c == '{') {
                checkMap.put('}', checkMap.getOrDefault('}', 0) + 1);
            }
            else if(c == '[') {
                checkMap.put(']', checkMap.getOrDefault(']', 0) + 1);
            }
            else if(checkMap.containsKey(c)) {		 // 如果此时遇到了一个有匹配的朝右括号的 朝左括号(说明之前遇到了与他匹配的朝左的括号,并且设置了键值对)
                checkMap.put(c,checkMap.get(c) - 1); // 把这个朝左括号所对应的次数减1
            }
            else {									 // 走到这里,说明是遇到了没有匹配的 朝左括号,即:在这个 朝左的 括号之前,没有出现过与他匹配的朝右的括号,那么直接返回false
                                                     // 例如:{) 、 {})等等
                return false;
            }
        }
        // 开始遍历value不等于0的key
        for (Map.Entry<Character, Integer> entry : checkMap.entrySet()) {  
            if(entry.getValue() != 0) {  
                return false;
            }
        }
        return true;
    }

但是。。。。似乎解决不了┓(;´_`)┏ 有一个测试用例是:

 这个测试用例似乎想测试:前一位是不是遍历过的元素。哈希法好像解决不了了呢,emmmmm,反正我是没想到解决方法了,留给以后解决吧 _(:3」∠❀)_ 累了累了,下一道了。

对了!最后,char类的包装类是:Character,集合定义泛型时记得别用错了。

 1047. 删除字符串中的所有相邻重复项

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

        思路,很简单,就是用栈去存储每一位字符,存入之前判断栈顶是否与之相同(第一次不用判断直接压入),如果相同(即相邻元素重复)则不存入,且弹出栈顶元素。

代码:

public String removeDuplicates(String s) {
        char[] ch = s.toCharArray();
        Deque<Character> check = new ArrayDeque<>();    // 栈比较好处理删除,但是输出结果的时候不方便,所以用双端队列
        for(char c : ch) { 
            if(check.isEmpty()){                        // 第一次,直接入队,无序判断删除
                check.addLast(c);
            }
            else if(c != check.peekLast()){                 
                check.addLast(c);
            }
            else{
                check.removeLast();                    // 遇到之前储存过的队列尾与待入队的字符相同,则删除掉队尾的这个字符
                continue;
            }
        }
        String result = "";
        while(!check.isEmpty()){
            result += check.removeFirst();
        }
        return result;
    }

        卡哥代码里也是用的Deque,但是方法是直接使用与Stack同名的push(压入元素)和pop(弹出栈顶元素)。我上一篇文章总结了双端队列(Deque)的常用方法以及Deque内部与队列和栈同名的方法。代码随想录里还有双指针法和用字符串作为栈的解法,比用队列速度更快,二刷再来吧,下一道下一道~。

代码随想录代码:

class Solution {
    public String removeDuplicates(String S) {
        //ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
        //参考:https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlist
        ArrayDeque<Character> deque = new ArrayDeque<>();
        char ch;
        for (int i = 0; i < S.length(); i++) {
            ch = S.charAt(i);
            if (deque.isEmpty() || deque.peek() != ch) {
                deque.push(ch);
            } else {
                deque.pop();
            }
        }
        String str = "";
        //剩余的元素即为不重复的元素
        while (!deque.isEmpty()) {
            str = deque.pop() + str;
        }
        return str;
    }
}

150. 逆波兰表达式求值

题目链接:150. 逆波兰表达式求值

        和上一道题思路很像啦,就是栈的应用,关键在于理解什么是后缀表达式吧,做着题还有一个问题是,Java中String类与其他类互相转换有忘了,待会儿总结一下。

代码:

class Solution {
	    /**
	        思路比较简单,就是利用栈来计算,遇到数字则进栈,遇到算术运算符则弹出两个栈顶元素进行计算,并将计算结果再次压入栈中,最终遍历完整个表达式后,弹出栈顶元素,即是结果
	     */
	    public int evalRPN(String[] tokens) {
	        Stack<Integer> temp = new Stack<>();
	        int result = 0;
            int a = 0;
            int b = 0;
	        for(int i = 0; i < tokens.length; i++) {
	            
	        	switch(tokens[i]){
	            case "+":
	            {
	            	b = temp.pop();
	            	a = temp.pop();
	            	result = a + b;
                    temp.push(result);  // 别忘了把结果再压入栈中
	            	continue;
	            }
                case "-":
	            {
	            	b = temp.pop();
	            	a = temp.pop();
	            	result = a - b;
                    temp.push(result);
	            	continue;
	            }
	            case "*":
	            {
	            	b = temp.pop();
	            	a = temp.pop();
	            	result = a * b;
                    temp.push(result);
	            	continue;
	            }
	            case "/":
	            {
	            	b = temp.pop();
	            	a = temp.pop();
	            	result = a / b;
                    temp.push(result);
	            	continue;
	            }
	            default:break;
	        	}
                // 不是运算符,那么就是数字了,直接压入
	        	temp.push(Integer.valueOf(tokens[i]));
	        }
            // 最终只剩下栈顶元素,直接弹出即是最终结果
	        return temp.pop();
	    }
	}

String类与其他类的相互转换:

String to Integer

  • 使用Integer.parseInt()Integer.valueOf()方法。
  • 示例:int num = Integer.parseInt("123");

String to Long

  • 使用Long.parseLong()Long.valueOf()方法。
  • 示例:long longNum = Long.parseLong("1234567890");

String to Float and Double

  • 使用Float.parseFloat()Double.parseDouble()方法。
  • 示例:float floatNum = Float.parseFloat("123.45");

String to Character

  • 对于单个字符的转换,通常使用String的charAt(0)方法。如果要获取整个字符串,可以创建一个字符数组,用String的toCharArray(str)方法
  • 示例:char[] ch = toCharArray("123"); 或 char ch = str.charAt(0); 其中 str 是字符串。

String to BigInteger

  • 使用new BigInteger(String)的构造函数。
  • 示例:BigInteger bigInt = new BigInteger("12345678901234567890");

String to BigDecimal

  • 使用new BigDecimal(String)的构造函数。
  • 示例:BigDecimal bd = new BigDecimal("12345678901234567890.1234567890");

自动装箱与拆箱:当将String转换为基本数据类型时,可以直接使用自动装箱(autoboxing)。反之,将基本数据类型转换为String时,可以使用对象的toString()方法或String的valueOf()方法。例如:

Integer boxedInt = Integer.parseInt("123"); // Integer自动装箱  
String intStr = boxedInt.toString(); // Integer对象的toString()方法返回String表示形式

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组找到长度最小的子数组,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值