[Leetcode Weekly Contest]350

链接:LeetCode

[Leetcode]2739. 总行驶距离

卡车有两个油箱。给你两个整数,mainTank 表示主油箱中的燃料(以升为单位),additionalTank 表示副油箱中的燃料(以升为单位)。
该卡车每耗费 1 升燃料都可以行驶 10 km。每当主油箱使用了 5 升燃料时,如果副油箱至少有 1 升燃料,则会将 1 升燃料从副油箱转移到主油箱。
返回卡车可以行驶的最大距离。
注意:从副油箱向主油箱注入燃料不是连续行为。这一事件会在每消耗 5 升燃料时突然且立即发生。

遍历即可。

class Solution {
    public int distanceTraveled(int mainTank, int additionalTank) {
        int res = 0;
        while(mainTank > 0) {
            if(mainTank < 5) {
                res += mainTank * 10;
                mainTank = 0;
            } else {
                res += mainTank/5 * 5 * 10;
                int added = Math.min(mainTank/5 , additionalTank);
                mainTank = mainTank % 5 + added;
                additionalTank -= added;
            }
        }
        return res;

    }
}

[Leetcode]2740. 找出分区值

给你一个 正 整数数组 nums 。
将 nums 分成两个数组:nums1 和 nums2 ,并满足下述条件:
数组 nums 中的每个元素都属于数组 nums1 或数组 nums2 。
两个数组都 非空 。
分区值 最小 。
分区值的计算方法是 |max(nums1) - min(nums2)| 。
其中,max(nums1) 表示数组 nums1 中的最大元素,min(nums2) 表示数组 nums2 中的最小元素。
返回表示分区值的整数

因为分区值和下标无关,因此先将序列排序。分区值的计算方法是两个元素的差值,因此序列中差值最小的两个元素就是答案的下界。

class Solution {
    public int findValueOfPartition(int[] nums) {
        Arrays.sort(nums);
        int res = nums[1]-nums[0];
        for(int i=1;i<nums.length;++i) {
            res = Math.min(res, nums[i] - nums[i-1]);
        }
        return res;
    }
}

[Leetcode]2741. 特别的排列

给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数。如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列:

  • 对于 0 <= i < n - 1 的下标 i ,要么 nums[i] % nums[i+1] == 0 ,要么 nums[i+1] % nums[i] == 0 。

请你返回特别排列的总数目,由于答案可能很大,请将它对 \(10^9 + 7\) 取余 后返回。

状压DP,我们需要知道当前还有哪些数(下标)可以选,以及上一个选的数(下标)是多少。
定义 dfs(i,j) 表示当前可以选的下标集合为 i,上一个选的数的下标是 j 时,可以构造出多少个特别排列。
枚举当前要选的数的下标 k,如果 nums[k] 与 nums[j] 满足题目整除的要求,
递归边界:dfs(0,j)=1,表示找到了一个特别排列。
递归入口:dfs(U∖{j},j),其中全集 U={0,1,2,⋯,n−1}。枚举特别排列的第一个数的下标 j,累加所有 dfs(U∖{j},j),即为答案。

class Solution {
    private static final int MOD = (int)1e9+7;

    public int specialPerm(int[] nums) {
        int n = nums.length;
        int[][] dp = new int[1<<n][n];

        for(int i=0;i<n;++i) dp[0][i] = 1;
        for(int i=0;i<(1<<n); ++i) {
            for(int j=0;j<n;++j) {
                for (int k = 0; k < n; ++ k) {
                    if (((i >> k) & 1) == 1 && (nums[j] % nums[k] == 0 || nums[k] % nums[j] == 0)) {
                        dp[i][j] = (dp[i][j] + dp[i ^ (1 << k)][k]) % MOD;
                    }
                }
            }
        }

        int res = 0;
        for(int i=0;i<n;++i) res = (res + dp[((1 << n) - 1)^(1<<i)][i]) % MOD;
        return res;
    }
}

[Leetcode]2741. 特别的排列

给你两个长度为 n 下标从 0 开始的整数数组 cost 和 time ,分别表示给 n 堵不同的墙刷油漆需要的开销和时间。你有两名油漆匠:
一位需要 付费 的油漆匠,刷第 i 堵墙需要花费 time[i] 单位的时间,开销为 cost[i] 单位的钱。
一位 免费 的油漆匠,刷 任意 一堵墙的时间为 1 单位,开销为 0 。但是必须在付费油漆匠 工作 时,免费油漆匠才会工作。
请你返回刷完 n 堵墙最少开销为多少。

class Solution {
    public int paintWalls(int[] cost, int[] time) {
        int n = cost.length;
        // 空间至少是 n, 最小价值。
        var f = new int[n + 1][n + 1];
        for (int[] a : f) Arrays.fill(a, Integer.MAX_VALUE/2);
        f[0][0] = 0; // 0 个物品,空间至少为 0,最小价值为 0
        for (int i = 1; i <= n; i++) { // i 个物品
            for (int j = 0; j <= n; j++) { // 空间至少为 j
                // f[i][j] = f[i - 1][j]; // 不选第 i 个物品,对应下标为 i - 1。
                // 选:空间至少为 0,负数时取 0。空间减少 time[i - 1] + 1,价值增加 cost[i - 1]。
                f[i][j] = Math.min(f[i - 1][j], f[i - 1][Math.max(j - time[i - 1] - 1, 0)] + cost[i - 1]);
            }
        }
        return f[n][n];
    }
}

参考:LeetCode

posted @ 2023-07-03 21:09  Jamest  阅读(20)  评论(0编辑  收藏  举报