[Leetcode Weekly Contest]286

链接:LeetCode

[Leetcode]2215. 找出两数组的不同

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,请你返回一个长度为 2 的列表 answer ,其中:

answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。
answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整数组成的列表。
注意:列表中的整数可以按 任意 顺序返回。。

哈希表,遍历即可。

class Solution {
    public List<List<Integer>> findDifference(int[] nums1, int[] nums2) {
        List<List<Integer>> res = new ArrayList<>();
        for(int i=0;i<2;++i) res.add(new ArrayList<Integer>());
        Set<Integer> s1 = new HashSet<>();
        Set<Integer> s2 = new HashSet<>();

        for(var n1:nums1) s1.add(n1);
        for(var n2:nums2) s2.add(n2);

        for(var n1:s1) {
            if(!s2.contains(n1)) res.get(0).add(n1);
        }
        for(var n2:s2) {
            if(!s1.contains(n2)) res.get(1).add(n2);
        }

        return res;
    }
}

[Leetcode]2216. 美化数组的最少删除数

给你一个下标从 0 开始的整数数组 nums ,如果满足下述条件,则认为数组 nums 是一个 美丽数组 :

nums.length 为偶数
对所有满足 i % 2 == 0 的下标 i ,nums[i] != nums[i + 1] 均成立
注意,空数组同样认为是美丽数组。

你可以从 nums 中删除任意数量的元素。当你删除一个元素时,被删除元素右侧的所有元素将会向左移动一个单位以填补空缺,而左侧的元素将会保持 不变 。

返回使 nums 变为美丽数组所需删除的 最少 元素数目。

遍历即可,可以设置一个标志位判断下标。

class Solution {
    public int minDeletion(int[] nums) {
        int res = 0;
        int n = nums.length;
        boolean flag = true;
        for(int i=0;i<n-1;++i) {
            if(flag && nums[i] == nums[i+1]) {
                 res ++;
            }
            else flag = !flag;
        }
        if(flag) res ++;
        return res;
    }
}

[Leetcode]2217. 找到指定长度的回文数

给你一个整数数组 queries 和一个 正 整数 intLength ,请你返回一个数组 answer ,其中 answer[i] 是长度为 intLength 的 正回文数 中第 queries[i] 小的数字,如果不存在这样的回文数,则为 -1 。

回文数 指的是从前往后和从后往前读一模一样的数字。回文数不能有前导 0 。

只看回文数的左半部分,可以发现左半部分是从 \(1000\cdots0\) 开始,逐渐增加的。反转这个数,拼到左半部分之后即为第 q 个长为 intLength 的回文数。

class Solution {
    public long[] kthPalindrome(int[] queries, int intLength) {
        int k = (intLength+1) / 2;
        int maxK = (int)(9 * Math.pow(10 , k-1));
        int n = queries.length;
        long[] res = new long[n];
        for(int i=0;i<n;++i) {
            int query = queries[i];
            res[i] = query > maxK ? -1 : getKthPalindrome(query, intLength, k);
        }
        return res;
    }

    public long getKthPalindrome(int query, int intLength, int k) {
        char[] res = new char[intLength];
        query --;
        for(int i=0;i<k;++i) {
            if(i == 0) res[i] = (char)(query / Math.pow(10, k-1)+'1');
            if(i !=0 ) res[i] = (char)(query / Math.pow(10, k-i-1)+'0');
            query = (int)(query % Math.pow(10, k-i-1));
        }
        int j = 0;
        for(int i=intLength-1;i>=k;--i) {
            res[i] = res[j];
            j++;
        }
        long result = 0L;
        for (var ch:res) {
            result = result * 10 + (ch-'0');
        }
        return result;
    }
}

[Leetcode]2218. 从栈中取出 K 个硬币的最大面值和

一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币。

每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里。

给你一个列表 piles ,其中 piles[i] 是一个整数数组,分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k ,请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少 。

朴素的,通过三维DP可以解答,但我们可以发现再每次循环时都需要对getCoinValue进行累加,这在同一个栈的循环中是浪费的,因为我们对于同一个i的栈,都需要计算其前缀。

class Solution {
    public int maxValueOfCoins(List<List<Integer>> piles, int k) {
        int n = piles.size();
        int[][] dp = new int[n][k+1];
        for(int i = 0;i<n;++i) {
            for(int j=0;j<k+1;++j) {
                if(j==0) dp[i][0] = 0;
                else if(i==0) dp[0][j] = piles.get(0).subList(0, Math.min(piles.get(0).size(), j)).stream().collect(Collectors.summingInt(Integer::intValue));
                else {
                    int getCoinValue = 0;
                    for(int getCoin = 0; getCoin <= Math.min(j, piles.get(i).size()); ++ getCoin) {
                        if(getCoin !=0 ) getCoinValue += piles.get(i).get(getCoin-1);
                        dp[i][j] = Math.max(dp[i][j], dp[i-1][j-getCoin] + getCoinValue);
                    }
                }
            }
        }
        return dp[n-1][k];
    }
}

因此,我们可以先对每个栈求其前缀和 \(\textit{sum}\)\(\textit{sum}\) 的第 \(j\) 个元素视作一个体积为 \(j\),价值为 \(\textit{sum}[j]\) 的物品。
问题转化成求从 n 个物品组里面取物品体积和为 k 的物品,且每组至多取一个物品时的物品价值最大和,即分组背包模型。

class Solution {
    public int maxValueOfCoins(List<List<Integer>> piles, int k) {
        var f = new int[k + 1];
        var sumN = 0;
        for (var pile : piles) {
            var n = pile.size();
            for (var i = 1; i < n; ++i)
                pile.set(i, pile.get(i) + pile.get(i - 1)); // pile 前缀和
            sumN = Math.min(sumN + n, k); // 优化:j 从前 i 个栈的大小之和开始枚举(不超过 k)
            for (var j = sumN; j > 0; --j)
                for (var w = 0; w < Math.min(n, j); ++w)
                    f[j] = Math.max(f[j], f[j - w - 1] + pile.get(w)); // w 从 0 开始,物品体积为 w+1
        }
        return f[k];
    }
}

Leetcode

posted @ 2022-05-19 22:08  Jamest  阅读(52)  评论(0编辑  收藏  举报