• [Leetcode Weekly Contest]295


    链接:LeetCode

    [Leetcode]2287. 重排字符形成目标字符串

    给你两个下标从 0 开始的字符串 s 和 target 。你可以从 s 取出一些字符并将其重排,得到若干新的字符串。

    从 s 中取出字符并重新排列,返回可以形成 target 的 最大 副本数。

    遍历即可。

    class Solution {
        public int rearrangeCharacters(String s, String target) {
            HashMap<Character, Integer> sCounter = new HashMap<>();
            HashMap<Character, Integer> targetCounter = new HashMap<>();
            for(var ch:s.toCharArray()) {
                sCounter.put(ch, sCounter.getOrDefault(ch, 0)+1);
            }
            for(var ch:target.toCharArray()) {
                targetCounter.put(ch, targetCounter.getOrDefault(ch, 0)+1);
            }
            int res = s.length();
            for(var ch:targetCounter.keySet()) {
                res = Math.min(res, sCounter.getOrDefault(ch,0)/targetCounter.get(ch));
            }
            return res;
        }
    }
    

    [Leetcode]2288. 价格减免

    句子 是由若干个单词组成的字符串,单词之间用单个空格分隔,其中每个单词可以包含数字、小写字母、和美元符号 '$' 。如果单词的形式为美元符号后跟着一个非负实数,那么这个单词就表示一个价格。
    例如 "$100"、"$23" 和 "$6.75" 表示价格,而 "100"、"$" 和 "2$3" 不是。
    注意:本题输入中的价格均为整数。

    给你一个字符串 sentence 和一个整数 discount 。对于每个表示价格的单词,都在价格的基础上减免 discount% ,并 更新 该单词到句子中。所有更新后的价格应该表示为一个 恰好保留小数点后两位 的数字。
    返回表示修改后句子的字符串。

    分隔每个单词,判断是否符合要求,减去折扣,把字符串拼回来。

    class Solution {
        public String discountPrices(String sentence, int discount) {
            String[] words = sentence.split(" ");
            for(int i=0;i<words.length;++i) {
                if(isPrice(words[i])) words[i] = getDisocunt(words[i], discount);
            }
            String res = "";
            for(int i=0;i<words.length;++i) {
                res += words[i];
                if(i!=words.length-1) res += " ";
            }
            return res;
        }
    
        public boolean isPrice(String word) {
            int n = word.length();
            if(word.charAt(0) != '$' || n < 2) return false;
            for(int i=1;i<n;i++) {
                if(word.charAt(i) > '9' || word.charAt(i) < '0') return false;
            }
            return true;
        }
    
        public String getDisocunt(String word, int discount) {
            long price = 0;
            for(int i=1;i<word.length();i++) {
                price  = price * 10 + (word.charAt(i)-'0');
            }
            return String.format("$%.2f", price/100.0*(100-discount));
        }
    }
    

    [Leetcode]2289. 使数组按非递减顺序排列

    给你一个下标从 0 开始的整数数组 nums 。在一步操作中,移除所有满足 nums[i - 1] > nums[i] 的 nums[i] ,其中 0 < i < nums.length 。

    重复执行步骤,直到 nums 变为 非递减 数组,返回所需执行的操作数。

    单调栈。
    对于每个 \(nums[i]\),如果它被消除,其要么是被 左侧第一个更大的元素 \(nums[j]\) 消除的,要么是下面的情况。
    这种情况是当 \(nums[j]\) 消除 \(nums[i]\) 之前,\(nums[j]\) 自身已经被 \(nums[k] (k < j)\) 消除。但是这种情况下,相当于 \(nums[k]\) 代替了 \(nums[j]\) 的位置,无论这种替换发生了多少次,都不会影响最终答案。因此 仍然只需考虑左侧第一大元素 \(nums[j]\) 即可。

    我们可以用 单调栈 求左侧第一个更大元素。(如果找不到左侧第一个更大元素,那么它永远不会被消除)

    \(nums[i]\)\(nums[j](j < i)\) 消除。那么,位于 j 和 i 之间的元素一定被首先消除,使得 \(nums[j]\)\(nums[i]\) 相邻,然后再是 \(nums[j]\) 消除 \(nums[i]\)。设 \(f[i]\)\(nums[i]\) 被消除所需的轮数,那么 \(f[i] = \displaystyle{\max(f[j+1]\dots f[i-1]) + 1}\) 可以在更新单调栈时同时统计。

    我们只需要统计 \([i+1,j-1]\) 中 仍然在单调栈里的元素 的步数中的最大值即可。因为那些不在单调栈里的元素,当它们被 pop 之后,一定会 push 进一个比他们的最大值 max 还大 1 的元素,因此这个被 push 进的元素可以 “代表” 所有被 pop 的元素。

    最终的答案就是 \(\max(f[i])\)

    class Solution {
        /**
        * [9   1   2   4    3    5    5]
        *
        * 9
        * -----------------------------6
        * ------------------------5
        * -------------4
        * -------------------3
        * --------2
        * ----1
        *
        *---------------------------------
        * 单调递减队列
        *到 1 的时候 9 在队列中 所以 1是 需要被删除的 时间点为 1
        *到 2 的时候 9 1 在队列中,要删除2需要先删除1, 时间点为 1 t(1)+1
        *到 4 的时候 9 2 在队列中,要删除4需要先删除2, 时间点为 2 t(2)+1
        *到 3 的时候 9 4 在队列中,要删除3不需要先删除其他的值,所以删除3的时间点为1
        *到 5 的时候 9 4 3 在队列中,要删除5 需要先删除 4,3,所以删除5的时间点为t(4)+1
        *到 6 的时候 9 5 在队列中,要删除6 需要先删除 5,所以删除6的时间点为t(5)+1
        */
        public int totalSteps(int[] nums) {
            int ans = 0;
            ArrayDeque<int[]> stack = new ArrayDeque<>();
            for (int num : nums) {
                //要删除当前num 的时间点
                int maxT = 0;
                //单调递减队列
                while (!stack.isEmpty() && stack.peek()[0] <= num) {
                    //左边小于等于num的值都需要在num被删除之前删掉,此时maxT 为删掉左边这些小与等于num的数的最大时间
                    maxT = Math.max(maxT, stack.pop()[1]);
                }
                //如果stack 不为空,所有还有左边还有比num值大的情况,表示num需要被删除,如果为空,说明num不用删除
                if (!stack.isEmpty()) {
                    maxT++;
                }
                stack.push(new int[]{num, maxT});
                ans = Math.max(ans, maxT);
            }
            return ans;
        }
    }
    

    [Leetcode]2290. 到达角落需要移除障碍物的最小数目

    给你一个下标从 0 开始的二维整数数组 grid ,数组大小为 m x n 。每个单元格都是两个值之一:

    • 0 表示一个 空 单元格,
    • 1 表示一个可以移除的 障碍物 。

    你可以向上、下、左、右移动,从一个空单元格移动到另一个空单元格。
    现在你需要从左上角 (0, 0) 移动到右下角 (m - 1, n - 1) ,返回需要移除的障碍物的 最小 数目。

    BFS。
    把障碍物当作可以经过的单元格,经过它的代价为 1,空单元格经过的代价为 0。我们可以用 Dijkstra,但还可以用 0-1 BFS 来将时间复杂度优化至 \(O(mn)\)

    class Solution {
        public int minimumObstacles(int[][] grid) {
            int n = grid.length, m = grid[0].length;
            int[][] res = new int[n][m];
            for(int i=0;i<n;++i){
                for(int j=0;j<m;++j){
                    res[i][j] = Integer.MAX_VALUE;
                }
            }
            res[0][0] = 0;
            //Queue<int[]> queue = new PriorityQueue<int[]>((a,b) -> res[a[0]][a[1]]-res[b[0]][b[1]]);
            ArrayDeque<int[]> queue = new ArrayDeque<>();
            queue.add(new int[] {0,0});
            while(!queue.isEmpty()) {
                int[] q = queue.pollFirst();
                int x = q[0], y = q[1];
                for(int i=0;i<4;++i) {
                    int new_x = x, new_y = y;
                    if(i==0) new_x--;
                    else if(i==1) new_x++;
                    else if(i==2) new_y--;
                    else if(i==3) new_y++;
                    if(new_x>=0 && new_x <=n-1 && new_y>=0&&new_y<=m-1 && (res[x][y]+grid[new_x][new_y] < res[new_x][new_y])) {
                        if(grid[new_x][new_y] == 0) queue.offerFirst(new int[]{new_x,new_y});
                        else queue.offerLast(new int[]{new_x,new_y});
                        res[new_x][new_y] = res[x][y]+grid[new_x][new_y];
                    }
                }
            }
            return res[n-1][m-1];
        }
    }
    

    参考:
    LeetCode
    LeetCode

  • 相关阅读:
    JAVA回调机制(转)
    单例模式之饿汉懒汉模式
    TOMCAT目录结构
    Hibernate Component的用法
    【转】单例模式完全剖析
    EhCache使用详解
    【转】jar包详解和METAINF作用
    使用 Spring 2.5 注释驱动的 IoC 功能
    vc中,制作在任务栏隐藏图标的mfc程序
    打开网页,打开外部应用程序
  • 原文地址:https://www.cnblogs.com/hellojamest/p/16444415.html
Copyright © 2020-2023  润新知