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

Posted 小懒懒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码随想录算法训练营第11天 | ● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重复项 ● 150. 逆波兰表达式求值相关的知识,希望对你有一定的参考价值。

 

第五章 栈与队列part02

今日内容: 

 

●  20. 有效的括号

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

●  150. 逆波兰表达式求值

 

 详细布置 

 

 20. 有效的括号 

 

讲完了栈实现队列,队列实现栈,接下来就是栈的经典应用了。 

 

大家先自己思考一下 有哪些不匹配的场景,在看视频 我讲的都有哪些场景,落实到代码其实就容易很多了。

 

题目链接/文章讲解/视频讲解:https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html

 

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

 

栈的经典应用。 

 

要知道栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。

 

题目链接/文章讲解/视频讲解:https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html

 150. 逆波兰表达式求值 

 

本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题 

 

题目链接/文章讲解/视频讲解:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html

 

 

往日任务

●  day 1 任务以及具体安排:训练营一期day 1 

●  day 2 任务以及具体安排:day 2 第一章数组

●  day 3 任务以及具体安排:day 3 第二章 链表

●  day 4 任务以及具体安排:day 4 第二章 链表

●  day 5 周日休息

●  day 6 任务以及具体安排:day 6 第三章 哈希表

●  day 7 任务以及具体安排:day 7 第三章 哈希表

●  day 8 任务以及具体安排:day 8 第四章 字符串

●  day 9 任务以及具体安排:day 9 第四章 字符串

●  day 10 任务以及具体安排:day 10 第四章 字符串

 

 

代码随想录算法训练营第六天 | 242.有效的字母异位词349. 两个数组的交集202. 快乐数1. 两数之和

有效的字母异位词

【力扣】242.有效的字母异位词

class Solution 
    public boolean isAnagram(String s, String t) 
        /*
         * 思路:
         * 用数组当做统计26个字母出现次数的哈希表
         * 
         * 参考:
         * https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D
         * %E5%BC%82%E4%BD%8D%E8%AF%8D.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%
         * 88%E6%9C%AC
         * 
         * 
         * 定义一个数组叫做record.用来上记录字符串s里字符出现的次数。
         * 需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。
         * 再遍历字符串s的时候,只需要将s[i]-'a'所在的元素做+1操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。
         * 这样就将字符串s中字符出现的次数,统计出来了。
         * 那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
         * 那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。
         * 最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
         * 时间复杂度为O(n),空间上因为定义的是一个常量大小的辅助数组,所以空间复杂度为O(1)。
         * 
         */
        int record[] = new int[26]; // 数组哈希表,记录每个字母的出现次数

        // 记录字符串s中每个字母出现的次数
        for (int i = 0; i < s.length(); i++) 
            int index = s.charAt(i) - 'a'; // 表示26个字母中的第几个字母
            record[index]++;
        

        // 如果字符串t含有某个字母,那么减一
        for (int i = 0; i < t.length(); i++) 
            int index = t.charAt(i) - 'a';
            record[index]--;
        

        // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
        for (int i : record) 
            if (i != 0) 
                return false;
            
        
        // record数组所有元素都为零0,说明字符串s和t是字母异位词
        return true;
    

两个数组的交集

【力扣】349. 两个数组的交集

class Solution 
    public int[] intersection(int[] nums1, int[] nums2) 
        /*
         * 思路:
         * 使用哈希集合hashSet
         * 
         * 参考:
         * https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84
         * %E4%BA%A4%E9%9B%86.html#_349-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4
         * %BA%A4%E9%9B%86
         * 
         * 注意题目特意说明:输出结果中的每个元素一定是唯一的,
         * 也就是说输出的结果的去重的,同时可以不考虑输出结果的顺序。
         * 
         * 如果用数组做哈希表,那么假设交集的数字只有5000,那么数组的下标得到4999,
         * 造成存储空间的极大浪费。也即,如果哈希值比较少、特别分散、跨度非常大,
         * 使用数组就造成空间的极大浪费。所以这个时候可以用哈希集合。
         * 
         * 本题将一个数组变成哈希集合,然后遍历另一个数组与此哈希集合比较,
         * 看是否出现过相同的元素。
         * 
         * 
         */

        // 排除异常条件:数组不存在,或数组长度为0
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) 
            return new int[0];
        

        Set<Integer> set1 = new HashSet<>(); // nums1数组的集合
        Set<Integer> interSet = new HashSet<>(); // 交集

        // 获得nums1数组的不重复元素
        for (int i : nums1) 
            set1.add(i);
        

        // 从nums2中找到与nums1数组相同的元素
        for (int i : nums2) 
            if (set1.contains(i)) 
                interSet.add(i);
            
        

        // 集合变为int数组
        // 注意hashset先变为stream,才能变为数组
        return interSet.stream().mapToInt(x -> x).toArray();
    

快乐数

【力扣】202. 快乐数

class Solution 
    public boolean isHappy(int n) 
        /*
         * 思路:哈希集合
         * 每次按快乐数公式计算的结果,一旦发现新的就存到哈希集合中,
         * 如果发现哈希集合中已经存在此数,那么停止计算。(因为遇到
         * 重复出现的数后,继续计算又会陷入循环当中)。
         * 
         * 最后检查这个重复的数是否为1。
         * 
         * 参考:
         * https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
         * 
         */

        Set<Integer> set = new HashSet<>();
        // 一直计算快乐数,直到遇到重复的为止
        // n!=1是因为题意说直到变成1,变成1就说明是快乐数满足条件可以退出循环了(1没必要再进入循环了)。
        while (n != 1 && !set.contains(n)) 
            set.add(n);
            n = getNextNumber(n); // 按快乐数公式计算下一个
        

        // 检查重复的数是否为1
        return n == 1;
    

    public int getNextNumber(int n) 
        /*
         * 计算快乐数
         */

        // 注意怎么取各个位的数字
        int result = 0;
        while (n != 0) 
            int tmp = n % 10; // 获得末位数
            result += tmp * tmp;
            n /= 10; // n的位数-1
        
        return result;
    

两数之和

【力扣】1. 两数之和

class Solution 
    public int[] twoSum(int[] nums, int target) 
        /*
         * 思路:哈希表 key:数据元素,value:数组元素对应的下表
         * 
         * 什么时候使用哈希法,当我们需要查询一个元素是否出现过,
         * 或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
         * 
         * 我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,
         * 需要使用 key value结构来存放,key来存元素,value来存下标,
         * 那么使用map正合适。
         * 
         * 再来看一下使用数组和set来做哈希法的局限:
         * 1、数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
         * 2、set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,
         * 不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x和y的下标。所以set也不能用。
         * 此时就要选择另一种数据结构:map。
         * 
         * 参考:
         * https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6
         * %80%9D%E8%B7%AF
         * 
         */
        // 存储满足题目条件的两个数的下标
        int result[] = new int[2];
        // 排除异常:如果数组为null或者数组长度为0
        if (nums == null || nums.length == 0) 
            return result;
        

        // map目的用来存放我们访问过的元素,因为遍历数组的时候,
        // 需要记录我们之前遍历过哪些元素和对应的下标,
        // 这样才能找到与当前元素相匹配的(也就是相加等于target)
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) 
            // 检查两数之和的另一个数是否存在哈希表中
            int tmp = target - nums[i];
            if (map.containsKey(tmp)) 
                result[1] = i;
                result[0] = map.get(tmp); // 获得下标
                break;
            
            // map存元素和对应的下标
            map.put(nums[i], i);
        
        return result;
    

以上是关于代码随想录算法训练营第11天 | ● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重复项 ● 150. 逆波兰表达式求值的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第14天 | ● 理论基础 ● 递归遍历 ● 迭代遍历 ● 统一迭代

代码随想录算法训练营第10天 | ● 理论基础 ● 232.用栈实现队列 ● 225. 用队列实现栈

代码随想录算法训练营第13天 | ● 239. 滑动窗口最大值 ● 347.前 K 个高频元素 ● 总结

代码随想录算法训练营第15天 | ● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉树 2

代码随想录算法训练营第14天|530.二叉搜索树的最小绝对差501.二叉搜索树中的众数236.二叉树的最近公共祖先

代码随想录算法训练营第17天 | ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和