月度归档: 2022年3月

LeetCode刷题【869】重新排序得到 2 的幂

给定正整数 n ,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。

如果我们可以通过上述方式得到 2 的幂,返回 true;否则,返回 false

 

示例 1:

输入:n = 1
输出:true

示例 2:

输入:n = 10
输出:false

 

提示:

  • 1 <= n <= 109
Related Topics
  • 数学
  • 计数
  • 枚举
  • 排序

  • 👍 146
  • 👎 0
  • 明明各方面都非常的符合题意,但是只击败了5.28%的勇者【怎么都在打表】

    emmm,emmm,emmm,能AC,海星

    思路什么的,就回溯,转2进制,判断除了第一位之后有没有其他的1

    class Solution {
    
        int[] arr;
    
        int[] sizeMap = {0,9,99,999,9999,99999,999999,9999999,99999999,999999999,2147483647};
    
    
        public boolean reorderedPowerOf2(int n) {
            if (n==0){
                return false;
            }
            int size = 0;
            //看看这个数字能转成多大的int[]数组,然后用来执行回溯
            for (int i = 0; i < sizeMap.length; i++) {
                if (sizeMap[i] >= n){
                    size = i;
                    break;
                }
            }
            arr = new int[size];
            //把n数字的个位置上的数字放入数组中
            while (n > 0){
                arr[--size] = n % 10;
                n /= 10;
            }
            //执行回溯
            return dfs(0,0,new boolean[arr.length]);
        }
    
        /**
         * 判断一个数字是否是2的幂
         * @param num
         * @return
         */
        public boolean isPowerOf2(int num){
            int[] intArr = toBinaryArr(num);
            for (int i = 1; i < intArr.length; i++) {
                //2的幂的二进制有一个特点,就是只有第一位是1,后面都是0,
                //从第二位开始判断但凡有一个数字等于1,就返回false
                if (intArr[i] == 1){
                    return false;
                }
            }
            //后面都没有1,只有第一位是1,那么返回true;
            return true;
        }
    
        /**
         * 把一个数字转换成二进制int[]数组
         * @param num
         * @return
         */
        public int[] toBinaryArr(int num){
            int size = 32;
            //最大就32位,往大了写,之间判断某个数字的二进制数字有多长有点麻烦
            int[] intArr = new int[size];
            while (num > 0 ){
                //依次余2赋值在每一位上
                intArr[--size] = num % 2;
                num = num >> 1;
            }
            //到这里就已经知道之前用了多少位了,返回一个新的不含前面多余0的二进制数数字
            int[] res = new int[32 - size];
            System.arraycopy(intArr,size,res,0,32-size);
            return res;
        }
    
        /**
         * 回溯算法
         * @param num 当前数字
         * @param idx 当前数字的位数的
         * @param used arr[]数组中哪些位置已经被用过了
         * @return
         */
        public boolean dfs(int num, int idx, boolean[] used){
            if (idx == arr.length ){
                //终止条件,判断下这个数是否是2的幂数
                if (isPowerOf2(num)){
                    return true;
                }
                return false;
            }
            //当前数字乘以10,准备在后面再加上一个数字
            num *= 10;
            for (int i = 0; i < arr.length; i++) {
                //第一位数字不能为0
                //或者这个位置的数字已经用过了,那么跳过到下一个选项
                if ((idx == 0 && arr[i] == 0) || used[i]){
                    continue;
                }
                //标记当前数字用过了
                used[i] = true;
                //构建了新数字num+arr[i] 然后处理下一个情况
                if (dfs(num+arr[i],idx+1,used)){
                    //如果能满足就直接终止
                    return true;
                }
                //回溯的重要操作,将状态改回
                used[i] = false;
            }
            //如果都不能满足,返回false
            return false;
        }
    
    }
    

    看了一圈好像都在打表。。。。
    我也凑个热闹吧

    class Solution {
    
        int[][] arr = {
            {1,1,0,0,0,0,0,0,0,0,0},
            {1,2,0,0,0,0,0,0,0,0,0},
            {1,4,0,0,0,0,0,0,0,0,0},
            {1,8,0,0,0,0,0,0,0,0,0},
            {2,1,6,0,0,0,0,0,0,0,0},
            {2,2,3,0,0,0,0,0,0,0,0},
            {2,4,6,0,0,0,0,0,0,0,0},
            {3,1,2,8,0,0,0,0,0,0,0},
            {3,2,5,6,0,0,0,0,0,0,0},
            {3,1,2,5,0,0,0,0,0,0,0},
            {4,0,1,2,4,0,0,0,0,0,0},
            {4,0,2,4,8,0,0,0,0,0,0},
            {4,0,4,6,9,0,0,0,0,0,0},
            {4,1,2,8,9,0,0,0,0,0,0},
            {5,1,3,4,6,8,0,0,0,0,0},
            {5,2,3,6,7,8,0,0,0,0,0},
            {5,3,5,5,6,6,0,0,0,0,0},
            {6,0,1,1,2,3,7,0,0,0,0},
            {6,1,2,2,4,4,6,0,0,0,0},
            {6,2,2,4,5,8,8,0,0,0,0},
            {7,0,1,4,5,6,7,8,0,0,0},
            {7,0,1,2,2,5,7,9,0,0,0},
            {7,0,1,3,4,4,4,9,0,0,0},
            {7,0,3,6,8,8,8,8,0,0,0},
            {8,1,1,2,6,6,7,7,7,0,0},
            {8,2,3,3,3,4,4,5,5,0,0},
            {8,0,1,4,6,6,7,8,8,0,0},
            {9,1,1,2,2,3,4,7,7,8,0},
            {9,2,3,4,4,5,5,6,6,8,0},
            {9,0,1,2,3,5,6,7,8,9,0},
            {10,0,1,1,2,3,4,4,7,7,8}
        };
    
        int[] sizeMap = {0,9,99,999,9999,99999,999999,9999999,99999999,999999999,2147483647};
    
        public boolean reorderedPowerOf2(int n) {
            if (n==0){
                return false;
            }
            int size = 0;
            //看看这个数字能转成多大的int[]数组
            for (int i = 0; i < sizeMap.length; i++) {
                if (sizeMap[i] >= n){
                    size = i;
                    break;
                }
            }
            int[] numArr = new int[size];
            //把n数字的个位置上的数字放入数组中
            while (n > 0){
                numArr[--size] = n % 10;
                n /= 10;
            }
            Arrays.sort(numArr);
            for (int[] ints : arr) {
                if (ints[0] == numArr.length){
                    int idx = 0;
                    while (++idx<=ints[0] && ints[idx] == numArr[idx-1]){}
                    if(--idx == ints[0] && ints[idx] == numArr[idx-1]){
                        return true;
                    }
                }
            }
            return false;
        }
    
    }
    

    LeetCode刷题【301】删除无效的括号

    给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。

    返回所有可能的结果。答案可以按 任意顺序 返回。

     

    示例 1:

    输入:s = "()())()"
    输出:["(())()","()()()"]
    

    示例 2:

    输入:s = "(a)())()"
    输出:["(a())()","(a)()()"]
    

    示例 3:

    输入:s = ")("
    输出:[""]
    

     

    提示:

    • 1 <= s.length <= 25
    • s 由小写英文字母以及括号 '('')' 组成
    • s 中至多含 20 个括号
    Related Topics
  • 广度优先搜索
  • 字符串
  • 回溯

  • 👍 681
  • 👎 0
  • 类似广度优先搜索的处理办法、JAVA(详细注释)

    括号字符串匹配问题我们常用的一个方法,遇到‘(’加1,遇到‘)’减1,结果为0的时候能表示形成完美匹配闭合。
    这个问题也可以类比的想象为出入栈问题,‘(’入栈,‘)’出栈
    另外,括号运算也可以类比的换算为其他结构,比如“树”
    这是一个非常有意思的话题,不过题归正传,回到我们这题上

    一顿分析

    自己搞个字符串分析下看看,第二行标记的对应的映射关系,第三行统计了求和的值

     (  (  )  (  )  )  )  )  (  )  )  (  (  (  )
     1  1 -1  1 -1 -1 -1 -1  1 -1 -1  1  1  1  -1
     1  2  1  2  1  0 -1
    

    当我们遇到这个和为-1的时候,很明显的说明了( ( ) ( ) ) )这段中有多余的)了,那么我们就把这段中的多余的)删掉一个再继续处理,可以得到如下两段,其中有一种连续的) )的情况删除任何一个结果都是一样的,这个可以再优化一下。

     (  (  )  (  )  ) 
     (  (  (  )  )  ) 
    

    取第一种情况继续分析,那么字符串就变成了

     (  (  )  (  )  )  )  (  )  )  (  (  (  )
     1  1 -1  1 -1 -1 -1  1 -1  -1 1  1  1  -1
     1  2  1  2  1  0 -1 
    

    再次遇到了-1继续同样的操作,在所有的结果中我们再取其中一种,以下省略数步,得到其中一个如下结果

     (  (  )  (  )  )  (  )  (  (  (  )
     1  2  1  2  1  0  1  0  1  2  3  2
    

    最终的结果为2,这是另外一种情况,对应的我们应该往前删除两个(,但是前面的(很多,我们应该删除哪两个呢?

    显然这个不能随意删除任意的(了,而是只能删除最后出现结果为0往后的位置中的(,但是这里面也有很多个(,又要删除哪两个呢?

    最直观的办法当然是枚举所有的可能性,但是额外再写个枚举组合的算法好像有点麻烦,那么我们不如每个位置的(都删除一下,生成对应个数的字符串,然后再次处理整个逻辑,直到最后多余的(都处理掉的情况。

    当然这里也直观的可以看到了重复( (的时候其实删除任意一个都是一样的,这个也许可以再优化一点点。

    那么整个逻辑都清楚了,下面看代码,已经加了一点点额外的剪枝优化,

    1. maxSize记录了已经得到的结果的最长长度,如果新的字符串比这个短就不用再处理了
    2. history记录了已经处理过的字符串的哈希表,如果已经处理过了就不用再处理这个了
    3. res结果先存入这个哈希表中,直接去重,防止有重复的结果被统计

    代码

    class Solution {
    
        HashSet<String> history = new HashSet<>();
        HashSet<String> res = new HashSet<>();
        public List<String> removeInvalidParentheses(String s) {
            Queue<String> queue = new LinkedList<>();
            //加入一个队列待处理
            queue.offer(s);
            //maxSize 记录下当前得到的符合预期的结果中最长的结果的长度
            int maxSize = 0;
            while (!queue.isEmpty()){
                String currentStr = queue.poll();
                if (currentStr.length()<maxSize){
                    //如果这个字符串的长度已经小于可行结果中的最大长度,那么说明再处理之后得到的结果也不是最少删减个数能得到的
                    continue;
                }
                //下标标记
                int idx = -1;
                //遇到"("加1,遇到")"减1 遍历到idx位置的时候得到的结果
                int total = 0;
                //最有一个total等于0的时候的位置,后面有多余的"("的时候要用到
                int lastZero = -1;
                //判断是否遇到了total=-1的情况,其实也可以在下面修改flag = false;的地方用跳出外面一层循环的写法
                boolean flag = true;
                while (++idx < currentStr.length() && flag){
                    if (currentStr.charAt(idx) == '('){
                        //遇到'('加1
                        total++;
                    }
                    if (currentStr.charAt(idx) == ')'){
                        ////遇到'('减1,其他都不用管
                        total--;
                    }
                    if (total==0){
                        //等于0的时候记录下最后0出现的位置
                        lastZero = idx;
                    }
                    //当到达某个下标的时候total=-1了,说明')'多了一个,需要在前面的所有')'中删除掉一个
                    if (total==-1){
                        //标记遇到-1的情况了
                        flag = false;
                        for (int i = 0; i <= idx; i++) {
                            //从头开始找')'
                            if (currentStr.charAt(i)==')'){
                                //删除掉指定位置的')',生成新字符串
                                String tmpStr = strDeleteIndex(currentStr,i);
                                //如果没有处理过这种字符串的话,把他加入到queue、并标记为已经处理过这种的
                                if (!history.contains(tmpStr)){
                                    history.add(tmpStr);
                                    queue.add(tmpStr);
                                }
                            }
                        }
                    }
                }
                //如果没有遇到total=-1的情况,说明这里已经遍历到字符串的结尾了
                if (flag){
                    //最终位置结果如果是大于0的,说明前面的lastZero位置到结束位置之间有多余的'('
                    if (total > 0){
                        //需要往前遍历找到最后一个0的位置lastZero从里面删除total个"("左括号,但是n个'('里面选total个'('不是太好处理,需要组合不同情况
                        //那么我们就换一个简单点的办法,每个'('都删除一下,生成一个字符串,并重新执行上面的之前的逻辑,即把删除了一个'('的字符串
                        //重新加进queue再处理一遍,每次处理一个'(',直到最终处理掉了所有多余的'('
                        int i = lastZero;
                        while (++i < currentStr.length()){
                            if (currentStr.charAt(i) == '('){
                                //和上面处理')'一样,删除当前位置的'(',并加入到queue再次处理
                                String tmpStr = strDeleteIndex(currentStr,i);
                                if (!history.contains(tmpStr)){
                                    history.add(tmpStr);
                                    queue.add(tmpStr);
                                }
                            }
                        }
                    }else if (total == 0 && currentStr.length() >= maxSize){
                        //正好能闭合的添加进结果集,
                        //另外再判断更新maxSize,如果是长度比已有结果短的字符串就不用处理了
                        maxSize = currentStr.length();
                        res.add(currentStr);
                    }
                }
            }
            List<String> l = new ArrayList<>();
            int finalMaxSize = maxSize;
            res.forEach(str->{
                if (str.length()== finalMaxSize){
                    //再判断一遍长度,这边我也不确定是不是需要,所以保险起见还是写下吧
                    l.add(str);
                }
            });
            return l;
        }
    
    
        /**
         * 删除字符串指定下标位置的字符的封装方法,返回一个新的删除了指定位置的字符的字符串
         * 由于调用的地方已经严格控制的idx不会越界,所以idx的越界问题就没有做判断处理
         * @param str 原始字符串
         * @param idx 待删除位置下标
         * @return 新的删除了指定位置字符的字符串
         */
        public String strDeleteIndex (String str, int idx){
            char[] arr = new char[str.length()-1];
            char[] origin = str.toCharArray();
            System.arraycopy(origin,0,arr,0,idx);
            System.arraycopy(origin,idx+1,arr,idx,arr.length-idx);
            return new String(arr);
        }
    }

    LeetCode刷题【剑指 Offer 48】最长不含重复字符的子字符串

    请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

     

    示例 1:

    输入: "abcabcbb"
    输出: 3 
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
    

    示例 2:

    输入: "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
    

    示例 3:

    输入: "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
         请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
    

     

    提示:

    • s.length <= 40000

    注意:本题与主站 3 题相同:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

    Related Topics
  • 哈希表
  • 字符串
  • 滑动窗口

  • 👍 392
  • 👎 0
  • 一般解法,一步步分析实现

    一顿分析

    以字符串abcabcbb为例

    1. a的时候,最长为1,这个没啥问题 此时为1
    2. ab的时候,前面有了a为1,而b又不在前面的a中,所以可以由前面的长度加1得到 此时为2
    3. abc的时候,和前面的情况一样,新增的字符c在前面的范围中不存在则继续加1长度 此时长度为3
    4. abca的时候,新增了个a,在前面不重复的长度为3的字符abc中找到了一个相同的,他的下标为0,那么只能从这个下标往后和新增的a组成最长不重复子串了,下标相差求得 此时长度为3
    5. abcab的时候,比前面又多了个b,再次在前面的一个最长子串中尝试寻找b,发现存在,得到其下标为1,照样当前下标和查找到的下标求得新的最长子串长度为3
    6. abcabc的时候,又多了个c,依旧重复上面的 此时长度为3
    7. abcabcb,比前面多了个b,前面一个的最长子串为abc,查找得到了有重复的b,下标为4,和当前下标5求得新的最长子串长度为2
    8. abcabcbb,再次和前面的最长子串cb比较查找,最终得到当前最长子串长度为1
    9. 最终所有的情况中最长的为3

    代码

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if (s.length() == 0){
                return 0;
            }
            char[] arr = s.toCharArray();
            int[] dp = new int[s.length()];
            dp[0] = 1;
            int idx = 0;
            int max = 1;
            while (++idx < s.length()){
                int existIdx = existIdx(arr,idx - dp[idx-1]-1,idx-1,arr[idx]);
                if (existIdx==-1){
                    dp[idx] = dp[idx-1]+1;
                }else{
                    dp[idx] = idx-existIdx;
                }
                max = Math.max(max,dp[idx]);
            }
            return max;
        }
    
        public int existIdx(char[] arr , int left , int right , char c){
            while (++left <= right){
                if (arr[left] == c){
                    return left;
                }
            }
            return -1;
        }
    }

    至于查找位置用的existIdx方法,这里的不同单个字符的数量比较有限,直接遍历查找即可。不是太大的性能问题

    LeetCode刷题【剑指 Offer 54】二叉搜索树的第k大节点

    给定一棵二叉搜索树,请找出其中第 k 大的节点的值。

     

    示例 1:

    输入: root = [3,1,4,null,2], k = 1
       3
      / \
     1   4
      \
       2
    输出: 4

    示例 2:

    输入: root = [5,3,6,2,4,null,null,1], k = 3
           5
          / \
         3   6
        / \
       2   4
      /
     1
    输出: 4

     

    限制:

    • 1 ≤ k ≤ 二叉搜索树元素个数
    Related Topics
  • 深度优先搜索
  • 二叉搜索树
  • 二叉树

  • 👍 265
  • 👎 0
  • 中序遍历(倒着)

    二叉搜索树、既然顺着中序遍历是连续递增的序列,先遍历右子树、然后跟节点、最后左子树这样的顺序来遍历的话,就是一个连续递减的序列了。

    再找第K大的也就轻而易举了。

    代码

    class Solution {
        int theK;
        int theNum = -1;
        public int kthLargest(TreeNode root, int k) {
            theK = k;
            dfs(root);
            return theNum;
        }
    
        public void dfs(TreeNode node){
            if (null == node){
                return;
            }
            dfs(node.right);
            if (theK==0){
                return;
            }
            theK--;
            if (theK==0){
                theNum = node.val;
                return;
            }
            dfs(node.left);
        }
    }

    LeetCode刷题【426】将二叉搜索树转化为排序的双向链表

    将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表

    对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

    特别地,我们希望可以 就地 完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中最小元素的指针。

     

    示例 1:

    输入:root = [4,2,5,1,3] 
    
    输出:[1,2,3,4,5]
    
    解释:下图显示了转化后的二叉搜索树,实线表示后继关系,虚线表示前驱关系。
    
    

    示例 2:

    输入:root = [2,1,3]
    输出:[1,2,3]
    

    示例 3:

    输入:root = []
    输出:[]
    解释:输入是空树,所以输出也是空链表。
    

    示例 4:

    输入:root = [1]
    输出:[1]
    

     

    提示:

    • -1000 <= Node.val <= 1000
    • Node.left.val < Node.val < Node.right.val
    • Node.val 的所有值都是独一无二的
    • 0 <= Number of Nodes <= 2000
    Related Topics
  • 深度优先搜索
  • 二叉搜索树
  • 链表
  • 二叉树
  • 双向链表

  • 👍 157
  • 👎 0
  • 二叉搜索树+中序遍历 = 前驱后继关系对应的递增序列

    一顿分析
    根据题意,要求重新对应前驱后继关系的链表,那么自然想到的就是二叉搜索树的中序遍历操作。

    那么我们就在中序遍历的过程中做文章

    1. 定义一个全局变量preNode,当前节点遍历结束的时候,把这个preNode指向到当前节点,这样到下一个节点的时候preNode指向的自然就是中序遍历的前一个节点,也就是当前节点的前驱节点
    2. 遍历到当前节点的时候,将preNoderight指向到当前节点,将当前节点的left指向到preNode,这样就算是完成了链表的基本链接操作
    3. 额外定义一个tmpNode,将他的right指向到我们在中序遍历过程中遇到的第一个节点,这样head那边的指针关系也关联上了
    4. 剩下最后的节点到指向到第一个节点的操作。在我们完成了上面所有操作之后preNode自然就是中序遍历的最后一个节点了,而tmpNoderight又指向了第一个节点,所以我们再在这时候将两者关联起来
    5. 结束收工

    代码

    class Solution {
    
        Node tmpNode = new Node();
        Node preNode;
    
        public Node treeToDoublyList(Node root) {
            if (null == root){
                return null;
            }
            dfs(root);
            preNode.right = tmpNode.right;
            tmpNode.right.left = preNode;
            return tmpNode.right;
        }
    
        public void dfs(Node node){
            if (null == node){
                return;
            }
            dfs(node.left);
            if (tmpNode.right == null){
                //把虚拟头结点连接到最小节点
                tmpNode.right = node;
            }
            if (preNode != null){
                //连起来
                preNode.right = node;
                node.left = preNode;
            }
            preNode = node;
            dfs(node.right);
        }
    
    }

    LeetCode刷题【剑指 Offer 34】二叉树中和为某一值的路径

    给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

    叶子节点 是指没有子节点的节点。

     

    示例 1:

    输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
    输出:[[5,4,11,2],[5,8,4,5]]
    

    示例 2:

    输入:root = [1,2,3], targetSum = 5
    输出:[]
    

    示例 3:

    输入:root = [1,2], targetSum = 0
    输出:[]
    

     

    提示:

    • 树中节点总数在范围 [0, 5000]
    • -1000 <= Node.val <= 1000
    • -1000 <= targetSum <= 1000

    注意:本题与主站 113 题相同:https://leetcode-cn.com/problems/path-sum-ii/

    Related Topics
  • 深度优先搜索
  • 回溯
  • 二叉树

  • 👍 307
  • 👎 0
  • 回溯DFS

    深度优先搜索回溯的一般应用题。
    相对的有一个比较类似但又不一样的题目可以结合起来一起学习理解【图解说明】DFS回溯+前缀和

    不同的是在437. 路径总和 III是求的路径上的区间合,需要借助前缀和的概念来处理。

    本题分析
    从根节点开始,往下DFS遍历,并记录路基上的节点合 和 节点的List集合
    当是根节点的时候,判断路径合是不是等于目标值,如果是把节点List集合塞进返回结果集里
    在退出当前节点遍历的时候,需要清除List集合中当前节点的值
    代码

    class Solution {
    
        List<List<Integer>> res = new ArrayList<>();
        int target;
        public List<List<Integer>> pathSum(TreeNode root, int target) {
            if (null == root){
                return new ArrayList<>();
            }
            this.target = target;
            dfs(root,0,new ArrayList<>());
            return res;
        }
    
    
        public void dfs(TreeNode node, int sum, List<Integer> list){
            if (node==null){
                return;
            }
            list.add(node.val);
            if (node.left == null && node.right == null){
                if (sum + node.val == target){
                    res.add(new ArrayList<>(list));
                }
                list.remove(list.size()-1);
                return;
            }
            dfs(node.left, sum + node.val,list);
            dfs(node.right,sum + node.val,list);
            list.remove(list.size()-1);
        }
    }
    

    LeetCode刷题【496】下一个更大元素 I

    nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧第一个 比 x 大的元素。

    给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。

    对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j]下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

    返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素

     

    示例 1:

    输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
    输出:[-1,3,-1]
    解释:nums1 中每个值的下一个更大元素如下所述:
    - 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
    - 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
    - 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

    示例 2:

    输入:nums1 = [2,4], nums2 = [1,2,3,4].
    输出:[3,-1]
    解释:nums1 中每个值的下一个更大元素如下所述:
    - 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
    - 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。
    

     

    提示:

    • 1 <= nums1.length <= nums2.length <= 1000
    • 0 <= nums1[i], nums2[i] <= 104
    • nums1nums2中所有整数 互不相同
    • nums1 中的所有整数同样出现在 nums2

     

    进阶:你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?

    Related Topics
  • 数组
  • 哈希表
  • 单调栈

  • 👍 661
  • 👎 0
  • JAVA 单调栈 【从前往后遍历的 & 从后往前遍历的】

    从后往前遍历的

    每次遍历到一个数字,从栈顶弹出比他小的所有数字,如果栈底还有数字说明这个数字是比当前遍历到的这个数字字后那个更大的数字。如果没有则说明没有更大的数字,得到-1

    class Solution {
        public int[] nextGreaterElement(int[] nums1, int[] nums2) {
            HashMap<Integer,Integer> hashMap = new HashMap<>();
            Stack<Integer> stack = new Stack<>();
            for (int i = nums2.length - 1; i >= 0; i--) {
                while (!stack.isEmpty() && stack.peek() < nums2[i]){
                    stack.pop();
                }
                if (stack.isEmpty()){
                    hashMap.put(nums2[i],-1);
                }else {
                    hashMap.put(nums2[i],stack.peek());
                }
                stack.push(nums2[i]);
            }
            int[] res = nums1;
            for (int i = 0; i < nums1.length; i++) {
                nums1[i] = hashMap.get(nums1[i]);
            }
            return nums1;
        }
    }
    从前往后遍历的

    每次弹出的时候,说明当前遍历的这个数字是被弹出的那个数字之后第一个比他大的数字

    class Solution {
        public int[] nextGreaterElement(int[] nums1, int[] nums2) {
            HashMap<Integer,Integer> map = new HashMap<>();
            Stack<Integer> stack = new Stack<Integer>();
            for (int numOf2 : nums2) {
                while (!stack.isEmpty() && stack.peek() < numOf2){
                    map.put(stack.pop(),numOf2);
                }
                stack.push(numOf2);
            }
            for (int i = 0; i < nums1.length; i++) {
                nums1[i] = map.getOrDefault(nums1[i], -1);
            }
            return nums1;
        }
    }