LeetCode 496. 下一个更大元素 I / 301. 删除无效的括号 / 869. 重新排序得到 2 的幂

496. 下一个更大元素 I

2021.10.26 每日一题

题目描述

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

示例 1:

输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

示例 2:

输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

提示:

1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 10^4
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

先用单调递减的栈找出每个元素右边第一个比它大的元素,比栈顶元素小,放入,比栈顶元素大,弹出并记录在map中,然后直接查找就可以了

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        //记得上次是不会做的,尽管是简单题
        //思路:要在O1内找到比当前大的
        //首先处理nums2,用栈处理,单调栈,找第一个比自己大的,存入map中
        int l = nums2.length;
        Stack<Integer> stack = new Stack<>();
        Map<Integer, Integer> map = new HashMap<>();

        stack.push(nums2[0]);
        for(int i = 1; i < l; i++){
            int temp = nums2[i];
            while(!stack.isEmpty() && temp > stack.peek()){
                int p = stack.pop();
                map.put(p, temp);
            }
            stack.push(temp);
        }
        while(!stack.isEmpty()){
            map.put(stack.pop(), -1);
        }
        int[] res = new int[nums1.length];
        for(int i = 0; i < nums1.length; i++){
            int temp = nums1[i];
            res[i] = map.get(temp);
        }
        return res;
    }
}

301. 删除无效的括号

2021.10.27 每日一题

题目描述

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

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

1 <= s.length <= 25
s 由小写英文字母以及括号 ‘(’ 和 ‘)’ 组成
s 中至多含 20 个括号

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-invalid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

又看范围,又看到不多,然后第一反应肯定又是回溯
先统计要删多少个左括号和右括号,然后回溯删除,用set去重

class Solution {
    Set<String> set = new HashSet<>();
    public List<String> removeInvalidParentheses(String s) {
        //看到数据范围,想到的是状态压缩,但仔细一想好像不行
        //然后再想栈,左边遍历一次,右边遍历一次,不行
        //先求出最少需要删除几个,然后再删除
        int l = s.length();

        int left = 0;   //要删除的左右括号的数量
        int right = 0;
        for(int i = 0; i < l; i++){
            char c = s.charAt(i);
            if(c == '(')
                left++;
            if(c == ')'){
                if(left > 0)
                    left--;     //匹配
                else
                    right++;    //无法匹配
            }
        }
        //这是left和right就是要删除的左右括号的数量

        //回溯删括号
        getRemove(s, left, right, 0, 0, 0);
        List<String> res = new ArrayList<>(set);
        //if(res.isEmpty()){
        //    res.add("");
        //}
        return res;
    }

    //当前位置,当前删除的左括号数量和右括号数量
    public void getRemove(String s, int left, int right, int idx, int lc, int rc){
        if(lc == left && rc == right){
            boolean flag = isValid(s);
            //如果是有效的,那么加到结果集中;否则返回
            if(flag)
                set.add(s);
            return;
        }
        //如果删多了,那么返回
        if(lc > left || rc > right)
            return;
        //如果剩下的数量不够了
        if(s.length() - idx < left - lc + right - rc)
            return;
        
        char c = s.charAt(idx);
        //如果当前字符不是括号,不管
        if(c != '(' && c != ')'){
            getRemove(s, left, right, idx + 1, lc, rc);
            return;
        }
        else if(c == '('){
            //删除当前字符
            String temp = s.substring(0, idx) + s.substring(idx + 1, s.length());
            getRemove(temp, left, right, idx, lc + 1, rc);
            
        }else if(c == ')'){
           String temp = s.substring(0, idx) + s.substring(idx + 1, s.length());
           getRemove(temp, left, right, idx, lc, rc + 1);
        }
        //回溯
        getRemove(s, left, right, idx + 1, lc, rc);
    }

    public boolean isValid(String s){
        int l = s.length();
        int left = 0;
        for(int i = 0; i < l; i++){
            char c = s.charAt(i);
            if(c == '(')
                left++;
            else if(c == ')'){
                left--;
                if(left < 0)
                    return false;
            }
        }
        return left == 0;
    }
}

没想到这个题也能用广度优先搜索,思路就是将字符串放在栈中,然后每次弹出当前字符串,因为可能重复,所以用set来代替栈更好
然后对当前字符串的每一个括号进行删除,然后放在新的set中,用新的set代替旧的set
每进行新的一轮时,set中的字符串长度都是相同的,所以判断当前set中的字符串有没有符合条件的,如果有符合条件的,那么直接输出就好了,因为长度是最大的

class Solution {
    public List<String> removeInvalidParentheses(String s) {
        //没想到这个也能广度优先
        //就是先删除一个括号,然后再扩展
        int l = s.length();
        List<String> res = new ArrayList<>();
        //用set充当栈的角色
        Set<String> set = new HashSet<>();

        set.add(s);

        while(true){
            //遍历所有的当前字符串,都是同一个长度的字符串
            for(String temp : set){
                if(isValid(temp))
                    res.add(temp);
            }
            //如果这个长度是有效的,那么输出,因为就是最短的长度
            if(res.size() > 0)
                return res;
            
            Set<String> cur = new HashSet<>();
            for(String temp : set){
                //遍历所有的字符
                for(int i = 0; i < temp.length(); i++){
                    char c = temp.charAt(i);
                    //如果和上一个字符相同,说明重复了,不需要考虑了
                    if(i > 0 && c == temp.charAt(i - 1))
                        continue;
                    if(temp.charAt(i) == '(' || temp.charAt(i) == ')'){
                        cur.add(temp.substring(0, i) + temp.substring(i + 1));
                    }
                }
            }
            set = cur;
        }
    }

    public boolean isValid(String s){
        int l = s.length();
        int left = 0;
        for(int i = 0; i < l; i++){
            char c = s.charAt(i);
            if(c == '(')
                left++;
            else if(c == ')'){
                left--;
                if(left < 0)
                    return false;
            }
        }
        return left == 0;
    }
}

三叶姐将删除变成添加,每次遍历到一个括号,需要看这个括号添加以后,是否依然能够满足条件,如果满足条件了并且长度也等于最后的长度了,那么就可以将这个字符串加到最后的结果集中
这样做可以不用最后一步判断这个字符串是否是合法的这一步操作

class Solution {
    Set<String> set = new HashSet<>();
    int n, max, len;
    String s;
    public List<String> removeInvalidParentheses(String _s) {
        s = _s;
        n = s.length();

        int l = 0, r = 0;
        for (char c : s.toCharArray()) {
            if (c == '(') {
                l++;
            } else if (c == ')') {
                if (l != 0) l--;
                else r++;
            }
        }
        len = n - l - r;
        
        int c1 = 0, c2 = 0;
        for (char c : s.toCharArray()) {
            if (c == '(') c1++;
            else if (c == ')') c2++;
        }
        max = Math.min(c1, c2);

        dfs(0, "", l, r, 0);
        return new ArrayList<>(set);
    }
    void dfs(int u, String cur, int l, int r, int score) {
        if (l < 0 || r < 0 || score < 0 || score > max) return ;
        if (l == 0 && r == 0) {
            if (cur.length() == len) set.add(cur);
        }
        if (u == n) return ;
        char c = s.charAt(u);
        if (c == '(') {
            dfs(u + 1, cur + String.valueOf(c), l, r, score + 1);
            dfs(u + 1, cur, l - 1, r, score);
        } else if (c == ')') {
            dfs(u + 1, cur + String.valueOf(c), l, r, score - 1);
            dfs(u + 1, cur, l, r - 1, score);
        } else {
            dfs(u + 1, cur + String.valueOf(c), l, r, score);
        }
    }
}


作者:AC_OIer
链接:https://leetcode-cn.com/problems/remove-invalid-parentheses/solution/gong-shui-san-xie-jiang-gua-hao-de-shi-f-asu8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

869. 重新排序得到 2 的幂

2021.10.28 每日一题

题目描述

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

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

示例 1:

输入:1
输出:true

示例 2:

输入:10
输出:false

示例 3:

输入:16
输出:true

示例 4:

输入:24
输出:false

示例 5:

输入:46
输出:true

提示:

1 <= N <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reordered-power-of-2
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

我的想法就是将所有2的幂都找出来,然后放在map集合中,然后判断所给的数,每个数字的个数是否相同

class Solution {
    static int base = 1;
    static Map<Integer, int[]> map = new HashMap<>();
    static{
        while(base <= (int)1e9){
            int[] nums = new int[10];
            int cur = base;
            while(base != 0){
                int temp = base % 10;
                nums[temp]++;
                base /= 10;
            }
            map.put(cur, nums);
            base = cur * 2;
        }
    }
    public boolean reorderedPowerOf2(int n) {
        int[] count = new int[10];
        while(n != 0){
            int temp = n % 10;
            count[temp]++;
            n /= 10;
        }

        for(Map.Entry<Integer, int[]> entry : map.entrySet()){
            int temp = entry.getKey();
            int[] nums = entry.getValue();

            for(int i = 0; i < 10; i++){
                if(nums[i] != count[i])
                    break;
                if(i == 9)
                    return true;
            }
        }
        return false;
    }
}

看到个简洁写法

class Solution{
    public boolean reorderedPowerOf2(int n) {
        // 将n变为从小到大排列
        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        // 查询
        for (int i = 1; i <= 1e9; i *= 2) {
            char[] temp = String.valueOf(i).toCharArray();
            Arrays.sort(temp);
            if(Arrays.equals(chars, temp)) return true;
        }
        return false;
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值