20200614力扣周赛

20200613第28场双周赛

1:商品折扣后的最终价格

题目

给你一个数组 prices ,其中 prices[i] 是商店里第 i 件商品的价格。商店里正在进行促销活动,如果你要买第 i 件商品,那么你可以得到与 prices[j] 相等的折扣,其中 j 是满足 j > i 且 prices[j] <= prices[i] 的 最小下标 ,如果没有满足条件的 j ,你将没有任何折扣。请你返回一个数组,数组中第 i 个元素是折扣后你购买商品 i 最终需要支付的价格。

示例 1:
输入:prices = [8,4,6,2,3]
输出:[4,2,4,2,3]
解释:
商品 0 的价格为 price[0]=8 ,你将得到 prices[1]=4 的折扣,所以最终价格为 8 - 4 = 4 。
商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2 。
商品 2 的价格为 price[2]=6 ,你将得到 prices[3]=2 的折扣,所以最终价格为 6 - 2 = 4 。
商品 3 和 4 都没有折扣。

示例 2:
输入:prices = [1,2,3,4,5]
输出:[1,2,3,4,5]
解释:在这个例子中,所有商品都没有折扣。

示例 3:
输入:prices = [10,1,1,6]
输出:[9,0,1,6]

题解

最先想到的就是暴力解法,维护一个数组sub作为每个prices[i]折扣的价格,那么结果数组中res的元素即为:
r e s [ i ] = p r i c e s [ i ] − s u b [ i ] res[i] = prices[i] - sub[i] res[i]=prices[i]sub[i]

class Solution {
    public int[] finalPrices(int[] prices) {
        int[] res = new int[prices.length];
        int[] sub = new int[prices.length];
        sub[prices.length - 1] = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                if (prices[j] <= prices[i]) {
                    sub[i] = prices[j];
                    break; 
                }
            }
        }
        for (int i = 0; i < prices.length; i++) {
            res[i] = prices[i] - sub[i];
        }
        return res;
    }
}

暴力解法的时间复杂度O(n2),

单调栈解法:

class Solution {
    public int[] finalPrices(int[] prices) {
        if (prices == null || prices.length <= 1) return prices;
        Deque<Integer> stack = new LinkedList<>();
        int[] res = new int[prices.length];
        for (int i = 0; i < prices.length; i++) {
            while (!stack.isEmpty() && prices[stack.peek()] >= prices[i]) {
                int pop = stack.pop();
                res[pop] = prices[pop] - prices[i];
            }
            stack.push(i);
        }
        while (!stack.isEmpty()) {
            int pop = stack.pop();
            res[pop] = prices[pop];
        }
        return res;
    }
}

20200614第193场双周赛

5436. 一维数组的动态和

题目

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。请返回 nums 的动态和。

示例 1:
输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。

示例 2:
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。

示例 3:
输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]

题解

此题其实就是前缀和(prefix sum),很容易即可解答:

class Solution {
    public int[] runningSum(int[] nums) {
        int[] ps = new int[nums.length];
        ps[0] = nums[0];
        for(int i = 1; i < nums.length; i++){
            ps[i] = ps[i - 1] + nums[i];
        }
        return ps;
    }
}

5437. 不同整数的最少数目

题目

给你一个整数数组 arr 和一个整数 k 。现需要从数组中恰好移除 k 个元素,请找出移除后数组中不同整数的最少数目。

示例 1:
输入:arr = [5,5,4], k = 1
输出:1
解释:移除 1 个 4 ,数组中只剩下 5 一种整数。

示例 2:
输入:arr = [4,3,1,1,3,3,2], k = 3
输出:2
解释:先移除 4、2 ,然后再移除两个 1 中的任意 1 个或者三个 3 中的任意 1 个,最后剩下 1 和 3 两种整数。

题解

用HashMap存储每个数组出现的次数,然后根据将数组按照出现次数从小到大排序,然后从数组开始移除k个元素,剩下的元素统计其不同元素个数(通过哈希集),得到结果个数即为结果。

class Solution {
    public int findLeastNumOfUniqueInts(int[] arr, int k) {
        Map<Integer, Integer> map = new HashMap<>(); //记录每个数字的个数
        for (int i = 0; i < arr.length; i++) {
            if (!map.keySet().contains(arr[i])) map.put(arr[i], 1);
            else {
                int update = map.get(arr[i]) + 1;
                map.put(arr[i], update);
            }
        }
        List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        List<Integer> sorted = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : list) {
            for (int i = 0; i < entry.getValue(); i++) {
                sorted.add(entry.getKey());
            }
        }
        Deque<Integer> linkedlist = new LinkedList<>();
        for (int i : sorted) linkedlist.add(i);
        for (int i = 0; i < k; i++) {
            linkedlist.pollFirst();
        }
        HashSet<Integer> set = new HashSet<>();
        for (int i : linkedlist) set.add(i);
        return set.size();
    }
}

上面是我写的代码,同样的思路,看了大佬的代码,觉得自己写的垃圾死了:

class Solution {
    public int findLeastNumOfUniqueInts(int[] arr, int k) {
        Map<Integer, Integer> cnt = new HashMap(arr.length);
        for(int x : arr){
            cnt.put(x, cnt.getOrDefault(x, 0) + 1);
        }
        
        List<Map.Entry<Integer, Integer>> list = new ArrayList(cnt.entrySet());
        list.sort((a, b) -> a.getValue().compareTo(b.getValue()));
        
        int ans = list.size();
        for(int i = 0; i < list.size(); i++){
            Map.Entry<Integer, Integer> ele = list.get(i);
            if(ele.getValue() > k){
                break;
            }
            ans--;
            k -= ele.getValue();
        }
        return ans;
    }
}

5438. 制作 m 束花所需的最少天数

题目

给你一个整数数组 bloomDay,以及两个整数 m 和 k 。现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。

示例 1:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _]   // 只能制作 1 束花
2 天后:[x, _, _, _, x]   // 只能制作 2 束花
3 天后:[x, _, x, _, x]   // 可以制作 3 束花,答案为 3

示例 2:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 2
输出:-1
解释:要制作 3 束花,每束需要 2 朵花,也就是一共需要 6 朵花。而花园中只有 5 朵花,无法满足制作要求,返回 -1 。
   
示例 3:
输入:bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
输出:12
解释:要制作 2 束花,每束需要 3 朵。
花园在 7 天后和 12 天后的情况如下:
7 天后:[x, x, x, x, _, x, x]
可以用前 3 朵盛开的花制作第一束花。但不能使用后 3 朵盛开的花,因为它们不相邻。
12 天后:[x, x, x, x, x, x, x]
显然,我们可以用不同的方式制作两束花。

示例 4:
输入:bloomDay = [1000000000,1000000000], m = 1, k = 1
输出:1000000000
解释:需要等 1000000000 天才能采到花来制作花束

示例 5:
输入:bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
输出:9

题解

class Solution {
    public int minDays(int[] b, int m, int k) {
        int inf = (int)1e9 + 1;
        int l = 0;
        int r = inf;
        while(l < r){
            int mid = (l + r) / 2;
            if(check(b, m, k, mid)){
                r = mid;
            }else{
                l = mid + 1;
            }
        }
        return l == inf ? -1 : l;
    }
    
    public boolean check(int[] b, int m, int k, int t){
        int cnt = 0;
        int total = 0;
        for(int i = 0; i < b.length; i++){
            if(b[i] > t){
                cnt = 0;
                continue;
            }
            cnt++;
            if(cnt == k){
                total++;
                cnt = 0;
            }
        }
        return total >= m;
    }
}

你可能感兴趣的:(算法)