LeetCode_单周赛_331

2558. 从数量最多的堆取走礼物

题意

给一组数字,每秒都选择最大的一个,留下其平方根

用 最大堆就行

code

class Solution {
    public long pickGifts(int[] g, int k) {
        long ans = 0;
        PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> (-(a - b)));
        for (int i = 0; i < g.length; i++) {
            ans += g[i];
            pq.add(g[i]);
        }
        while (pq.size() > 0 && k-- > 0) {
            int t = pq.poll();
            int a = (int) Math.sqrt(t);
            t -= a;
            ans -= t;
            // System.out.println(a + " " + t);
            pq.add(a);
        }

        return ans;
    }
}

2559. 统计范围内的元音字符串数

题意

给一个字符串数组,和 [ l, r ],求数组中下标在 [ l, r ] 范围内的字符串中,以元音字母 aeiou 作为开头和结尾的字符串数量

前缀和
求字符串数组的前缀和即可

code

class Solution {
     // 前缀和
    public int[] vowelStrings(String[] w, int[][] q) {
        int n = w.length;
        boolean[] vis = new boolean[26];
        vis[0] = true; vis[4] = true; vis[8] = true; vis[14] = true; vis[20] = true;
        int[] s = new int[n + 5];
        for (int i = 0; i < n; i++) {
            int t = 0;
            int a = w[i].length();
            if (vis[w[i].charAt(0) - 'a'] && vis[w[i].charAt(a - 1) - 'a']) t = 1;
            s[i + 1] = s[i] + t;
        }
        ArrayList<Integer> ans = new ArrayList<>();
        for (var t : q) {
            int a = s[t[1] + 1] - s[t[0]];
            ans.add(a);
        }
        int[] a = new int[ans.size()];
        for (int i = 0; i < ans.size(); i++) {
            a[i] = ans.get(i);
        }
        return a;
    }
}

2560. 打家劫舍 IV

题意

一排连续的房屋,偷钱,

  1. 不能偷相邻的房子
  2. 最少要偷 k 间房子。
    问:
    **偷钱能力:**这一次偷的所有的房子中,最大的金额
    满足以上两个条件的情况下,小偷的 最小偷钱能力是多少

求 最大值中的最小值,考虑二分求答案
求出数组中金额的 max 和 min,作为二分的区间

如果当前的 max 满足 check,则 >= max 都满足,向 < max 二分

用 check 函数作为二分的判断
求 check 函数时,当前房子金额 <= x && 隔壁没被偷过,就满足情况,贪心求,尽可能多偷,最后判断是否至少偷了 k 个房子即可。

有没有可能得到不在数组中的数
不可能
设 x 是二分到的不在数组中的数,它满足条件,y 是数组中小于 x 的最大的数
我们的条件是 [ 当前房子金额 <= x ] ,如果 x 满足条件,则 y 偷的房子是和 x 一样多的,最终会回归到数组中的数

code

class Solution {
    // check函数作为二分的条件,是 dp / 贪心
    // 题目是 求最小的最大值,用二分来搜索答案
    public int minCapability(int[] nums, int k) {
        int mx = nums[0], mn = nums[0]; // 存储最大最小值,用于二分
        for (var i : nums) {
            mx = Math.max(mx, i);
            mn = Math.min(mn, i);
        }

        int l = mn, r = mx;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(nums, mid, k)) r = mid;
            else l = mid + 1;
        }

        return l;
    }

    private boolean check(int[] a, int x, int k) { // 设最大的金额是 x,最少盗取 k 户
        int ans = 0; // 盗取的房子数量
        for (int i = 0, j = -2; i < a.length; i++) {
            if (a[i] <= x && j + 1 < i) {
                ans++;
                j = i;
            }
        }
        return ans >= k;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值