Leetcode刷题 2021.02.09

Leetcode992 K 个不同整数的子数组

给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定不同的子数组为好子数组。

(例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。)

返回 A 中好子数组的数目。

明天要回家过年了,不知道有没有时间更新博客了,还是希望博客连续更新不断吧。
今天的每日一题,困难题考查的的技巧方面就比较多了,如果没有一定的算法训练的话还真的是做不出。其实就是把中等题改了一下,但是怎么想得到的话就是另一回事了。

class Solution {
    
    
    public int subarraysWithKDistinct(int[] A, int K) {
    
    
        //恰好k个等于最多k个减去最多k - 1个。
        return helper(A, K) - helper(A, K - 1);
    }

    //至多包含k个不同整数的子数组
    private int helper(int[] A, int K){
    
    
        int n = A.length;
        int[] map = new int[n + 1];
        int i = 0, j = 0, count = 0, res = 0;
        while (j < n){
    
    
        	//增大右窗口,维护一个数组,记录不同整数的个数
            if (map[A[j]] == 0) count++;
            map[A[j]]++;
            //如果不满足条件了,就缩小左窗口
            while (count > K){
    
    
                map[A[i]]--;
                if (map[A[i]] == 0) count--;
                i++;
            }
            //比如[1,2,1,2],i = 0, j = 3时,有4个满足条件,即[2], [1,2], [2,1,2], [1,2,1,2]。就是以2为末尾的四个子数组
            res += j - i + 1;
            j++;
        }
        return res;
    }
}

Leetcode475 供暖器

冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。

在加热器的加热半径范围内的每个房屋都可以获得供暖。

现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。

说明:所有供暖器都遵循你的半径标准,加热的半径也一样。

求一个最小值,二分查找的老套路了,不断尝试并且收缩区间,直到某一个最小值符合条件就行了。

class Solution {
    
    
    public int findRadius(int[] houses, int[] heaters) {
    
    
        int i = 0, j = 1_000_000_000;
        //二分查找模板,数组没说是有序的,先排序一下
        Arrays.sort(houses);
        Arrays.sort(heaters);
        while (i < j){
    
    
            int mid = i + (j - i) / 2;
            if (helper(houses, heaters, mid)){
    
    
                j = mid;
            }else{
    
    
                i = mid + 1;
            }
        }
        return i;
    }

    private boolean helper(int[] houses, int[] heaters, int mid){
    
    
        int index = 0, n = houses.length;
        //看看每个供暖期是否都能覆盖到所有的房屋
        for(int i = 0; i < heaters.length; i++){
    
    
            int left = heaters[i] - mid, right = heaters[i] + mid;
            //如果在半径内,就说明可以覆盖
            while (index < n && houses[index] >= left && houses[index] <= right){
    
    
                index++;
            }
            if (index >= n) break;
            //如果当前的房屋大于左边的半径,说明肯定不能覆盖到了
            if (houses[index] < left) return false;
        }
        return index < n ? false : true;
    }
}

Leetcode1702 吃苹果的最大数目

有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,树上会长出 apples[i] 个苹果,这些苹果将会在 days[i] 天后(也就是说,第 i + days[i] 天时)腐烂,变得无法食用。也可能有那么几天,树上不会长出新的苹果,此时用 apples[i] == 0 且 days[i] == 0 表示。

你打算每天 最多 吃一个苹果来保证营养均衡。注意,你可以在这 n 天之后继续吃苹果。

给你两个长度为 n 的整数数组 days 和 apples ,返回你可以吃掉的苹果的最大数目。

贪心的思想,就好比平时吃东西,肯定是先把离保质期最近的吃到。可以用优先队列进行模拟,按过期时间从小到达排列,遍历的时候如果吃光了或者过了保质期了就出队。

class Solution {
    
    
    public int eatenApples(int[] apples, int[] days) {
    
    
        PriorityQueue<Node> queue = new PriorityQueue<>((x, y) -> (x.expire - y.expire));
        int res = 0;
        for(int i = 0; i < apples.length || !queue.isEmpty(); i++){
    
    
        //如果有苹果就加到队列里
            if (i < apples.length && apples[i] != 0){
    
    
                queue.offer(new Node(apples[i], i + days[i]));
            }
            //吃光了或者过了保质期了就出队
            while(!queue.isEmpty() && (queue.peek().expire<= i || queue.peek().num == 0)){
    
    
                queue.poll();
            }
            //吃到离保质期最近的一个苹果,同时吃掉的总数加1
            if (!queue.isEmpty()){
    
    
                queue.peek().num--;
                res++;
            }
        }
        return res;

    }
	//新建一个类,包含苹果的数目和过期时间
    class Node{
    
    
        int num;
        int expire;

        public Node(int num, int expire){
    
    
            this.num = num;
            this.expire = expire;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43447128/article/details/113777297