ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[Leetcode Weekly Contest]301

2022-07-18 09:39:18  阅读:211  来源: 互联网

标签:Contest int 301 位置 因子 MX amount 数组 Leetcode


链接:LeetCode

[Leetcode]2335. 装满杯子需要的最短总时长

现有一台饮水机,可以制备冷水、温水和热水。每秒钟,可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。
给你一个下标从 0 开始、长度为 3 的整数数组 amount ,其中 amount[0]、amount[1] 和 amount[2] 分别表示需要装满冷水、温水和热水的杯子数量。返回装满所有杯子所需的 最少 秒数。

简单贪心。
肯定是最好每次都选两个。分两种情况,一种是有一种水特别多,那么答案就是这种水的数量。否则,一定可以匹配到只剩一杯,或匹配完。

class Solution {
    public int fillCups(int[] amount) {
        Arrays.sort(amount);
        if(amount[2] == 0) return 0;
        if(amount[2] > amount[0] + amount[1]) return amount[2];
        else return 1+fillCups(new int[]{amount[0], amount[1]-1, amount[2]-1});
    }
}

[Leetcode]2336. 无限集中的最小数字

现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, ...] 。
实现 SmallestInfiniteSet 类:

  • SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。
  • int popSmallest() 移除 并返回该无限集中的最小整数。
  • void addBack(int num) 如果正整数 num 不 存在于无限集中,则将一个 num 添加 到该无限集中。

逆向思维,既然原来的集合是无限的,那我就构造一个有限的。 收集被无限集踢掉的元素、踢掉被无限集收录的元素。

class SmallestInfiniteSet {
    HashSet<Integer> removeSet = new HashSet<>();
    int cur = 1;

    public SmallestInfiniteSet() {
    }

    public int popSmallest() {
        int res = cur;
        while(removeSet.contains(res)) {
            res++;
        }
        removeSet.add(res);
        cur = res+1;
        return res;
    }

    public void addBack(int num) {
        cur = Math.min(cur, num);
        if(removeSet.contains(num)) removeSet.remove(num);
    }
}

/**
 * Your SmallestInfiniteSet object will be instantiated and called as such:
 * SmallestInfiniteSet obj = new SmallestInfiniteSet();
 * int param_1 = obj.popSmallest();
 * obj.addBack(num);
 */

[Leetcode]2337. 移动片段得到字符串

给你两个字符串 start 和 target ,长度均为 n 。每个字符串 仅 由字符 'L'、'R' 和 '_' 组成,其中:

  • 字符 'L' 和 'R' 表示片段,其中片段 'L' 只有在其左侧直接存在一个 空位 时才能向 左 移动,而片段 'R' 只有在其右侧直接存在一个 空位 时才能向 右 移动。
  • 字符 '_' 表示可以被 任意 'L' 或 'R' 片段占据的空位。

如果在移动字符串 start 中的片段任意次之后可以得到字符串 target ,返回 true ;否则,返回 false 。

双指针 + 字符串模拟。

class Solution {
    public boolean canChange(String start, String target) {
        int n = start.length();
        int l = 0;
        for(int r=0;r<n;++r) {
            if(target.charAt(r) == '_') continue;
            else {
                char ch = target.charAt(r);
                while(l<n && start.charAt(l) == '_') {
                    ++l;
                }
                if(l>=n) return false;
                if(start.charAt(l)!=target.charAt(r))return false;
                if(target.charAt(r)=='L' && r>l)return false;
                if(target.charAt(r)=='R' && r<l)return false;
                ++l;
            }
        }
        while(l<n) {
            if(start.charAt(l) != '_') return false;
            l++;
        }
        return true;
    }
}

[Leetcode]2338. 统计理想数组的数目

给你两个整数 n 和 maxValue ,用于描述一个 理想数组 。
对于下标从 0 开始、长度为 n 的整数数组 arr ,如果满足以下条件,则认为该数组是一个 理想数组 :

  • 每个 arr[i] 都是从 1 到 maxValue 范围内的一个值,其中 0 <= i < n 。
  • 每个 arr[i] 都可以被 arr[i - 1] 整除,其中 0 < i < n 。

返回长度为 n 的 不同 理想数组的数目。由于答案可能很大,返回对 \(10^9 + 7\) 取余的结果。

组合数。分别考虑以x结尾长度为n的理想数组有多少个,数组结尾可以是1 ~ maxValue,因此把这些情况累加,就是最终结果。
以结尾为4、长度为5进行分析:
4的前面可以是4、2、1, 2的前面可以是2、1, 1的前面只能是1。例如:
[1, 2, 2, 4, 4]
[1, 1, 1, 4, 4]
[2, 2, 2, 4, 4]
[4, 4, 4, 4, 4]
以[1, 2, 2, 4, 4]为例,可以记为 \([\_, *2, \_, *2, \_]\),只需记录在哪些位置的元素发生了改变(倍增),
从当前倍增的位置开始 ~ 下一次倍增的位置之前(或数组结尾),将会一直维持这个值。
可假设每个数组的开头前面有一个值1,若数组中的第一个元素为1,则没有发生倍增;若第一个元素不是1,则发生了倍增。
例如:[2, 2, 2, 4, 4] 可表示为 \([*2, \_, \_, *2, \_]\);
在同一个位置可以发生多次倍增,例如:[1, 1, 1, 4, 4] 可表示为 \([\_, \_, \_, *2*2, \_]\);[4, 4, 4, 4, 4] 可表示为 \([*2*2, \_, \_, \_, \_]\)。
由于固定了结尾为4,而4的质因子为2、2,即 4 = (1) * 2 * 2
所有结尾为4、长度为5的理想数组,问题可转化为 结尾数字(4)的质因子可以放在哪些位置,当前有5个不同的位置,2个质因子2,
从5个位置中选择一个(将2个2放在一个位置)或两个(将2个2放在不同位置),因为2个2是相同的,谁先谁后,结果都是一样的。所以这是个组合问题。
问题进一步转化为隔板法:把k个相同的小球放进n个不同的盒子中,允许有些盒子为空,也允许一个盒子中放入多个小球,有多少种不同的放法?
该问题可用隔板法来求解,把n个盒子当做n-1个隔板,然后加上k个小球,相当于总共有 n-1 + k 个位置,从中选出n-1个位置放隔板,
即方案数为:C(n-1+k)(n-1)
由于maxValue <= 104,质因子最小为2,213 = 8192 < 10^4 < 16384 = 2^14,质因子越大,质因子的个数将会越小,
所以质因子为2时,质因子的个数k才能达到最大值13,即 k <= 13。所以上面的 C(n-1+k)(n-1) 可写为 C(n-1+k)(k) ,k 显然远小于n-1.
若结尾数字由多个不同的质因子组成,例如:k1个2、k2个3、k3个5,则可将问题分解为:
1、从n-1 + k1个位置中选出k1个位置放质因子2,得到 C(n-1+k1)(k1)
2、从n-1 + k2个位置中选出k2个位置放质因子3,得到 C(n-1+k2)(k2)
3、从n-1 + k3个位置中选出k3个位置放质因子5,得到 C(n-1+k3)(k3)
这3种情况之间互不影响:放质因子5的时候,不用关心这个位置之前放没放过2、3,以及放了多少个2、多少个3。
所以可采用乘法原理来计算最终结果:C(n-1+k1)(k1) * C(n-1+k2)(k2) * C(n-1+k3)(k3)

综上,原问题最终转化为:质因数分解出所有的质因子及其个数(其实只关注个数k) + 计算组合数问题
计算组合数问题 可用动态规划进行计算,假设dp[i][j] 表示从i个位置中选择j个,即 C(i)(j)。该问题可分为两种情况:
1、选择了位置i,则只需再从i-1个位置中选择j-1个,即 C(i-1)(j-1)
2、未选择位置i,则需要从i-1个位置中选择j个,即 C(i-1)(j)
所以,dp[i][j] = dp[i-1][j-1] + dp[i-1][j]

class Solution {
    static final int MOD = (int) 1e9 + 7, MX = (int) 1e4 + 1, MX_K = 13; // 至多 13 个质因数
    static List[] ks = new List[MX]; // ks[x] 为 x 分解质因数后,每个质因数的个数列表
    static int[][] c = new int[MX + MX_K][MX_K + 1]; // 组合数

    static {
        for (var i = 1; i < MX; i++) {
            ks[i] = new ArrayList<Integer>();
            var x = i;
            for (var p = 2; p * p <= x; ++p) {
                if (x % p == 0) {
                    var k = 1;
                    for (x /= p; x % p == 0; x /= p) ++k;
                    ks[i].add(k);
                }
            }
            if (x > 1) ks[i].add(1);
        }

        c[0][0] = 1;
        for (var i = 1; i < MX + MX_K; ++i) {
            c[i][0] = 1;
            for (var j = 1; j <= Math.min(i, MX_K); ++j)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
        }
    }

    public int idealArrays(int n, int maxValue) {
        var ans = 0L;
        for (var x = 1; x <= maxValue; ++x) {
            var mul = 1L;
            for (var k : ks[x]) mul = mul * c[n + (int) k - 1][(int) k] % MOD;
            ans += mul;
        }
        return (int) (ans % MOD);
    }
}

参考:LeetCode

标签:Contest,int,301,位置,因子,MX,amount,数组,Leetcode
来源: https://www.cnblogs.com/hellojamest/p/16489246.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有