力扣第339场周赛

文章包含了三个编程问题的解决方案:找出给定二进制字符串中最长的平衡子字符串长度;创建一个满足特定条件的二维数组;以及在两只老鼠和多块奶酪的场景中,找到第一只老鼠吃掉指定数量奶酪的最大得分。解答涉及字符串处理、数组操作以及优化算法(如动态规划和回溯法)。

目录

6362. 最长平衡子字符串

6363. 转换二维数组

6364. 老鼠和奶酪


6362. 最长平衡子字符串

给你一个仅由 0 和 1 组成的二进制字符串 s 。  如果子字符串中 所有的 0 都在 1 之前 且其中 0 的数量等于 1 的数量,则认为 s 的这个子字符串是平衡子字符串。请注意,空子字符串也视作平衡子字符串。 返回  s 中最长的平衡子字符串长度。子字符串是字符串中的一个连续字符序列。

示例 1:

输入:s = "01000111"
输出:6
解释:最长的平衡子字符串是 "000111" ,长度为 6 。

示例 2:

输入:s = "00111"
输出:4
解释:最长的平衡子字符串是 "0011" ,长度为  4 。

示例 3:

输入:s = "111"
输出:0
解释:除了空子字符串之外不存在其他平衡子字符串,所以答案为 0 。

提示:

  • 1 <= s.length <= 50
  • '0' <= s[i] <= '1'
class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        int n = s.length();
        if(n < 2) return 0;
        int res = 0;
        for(int i = 0; i < n - 1; i++){
            if(s.charAt(i) == '0' && s.charAt(i + 1) == '1'){
                int j = i, k = i + 1;
                while(j >= 0 && k < n && s.charAt(j) == '0' && s.charAt(k) == '1'){
                    --j;
                    ++k;
                }
                res = Math.max(res, k - j - 1);
            }
        }
        return res;
    }
}

6363. 转换二维数组

给你一个整数数组 nums 。请你创建一个满足以下条件的二维数组:

  • 二维数组应该  包含数组 nums 中的元素。
  • 二维数组中的每一行都包含 不同 的整数。
  • 二维数组的行数应尽可能  。

返回结果数组。如果存在多种答案,则返回其中任何一种。请注意,二维数组的每一行上可以存在不同数量的元素。

示例 1:

输入:nums = [1,3,4,1,2,3,1]
输出:[[1,3,4,2],[1,3],[1]]
解释:根据题目要求可以创建包含以下几行元素的二维数组:
- 1,3,4,2
- 1,3
- 1
nums 中的所有元素都有用到,并且每一行都由不同的整数组成,所以这是一个符合题目要求的答案。
可以证明无法创建少于三行且符合题目要求的二维数组。

示例 2:

输入:nums = [1,2,3,4]
输出:[[4,3,2,1]]
解释:nums 中的所有元素都不同,所以我们可以将其全部保存在二维数组中的第一行。

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= nums.length
class Solution {
    public List<List<Integer>> findMatrix(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        int m = 0;
        for(int i = 0; i < nums.length; ++i){
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
            m = Math.max(map.get(nums[i]), m);
        }
        List<List<Integer>> res = new ArrayList<>();
        for(int i = 0 ; i < m; i++) res.add(new ArrayList<Integer>());
        int index = 0;
        while(index < m){
            for(Integer key: map.keySet()) {
                if(map.get(key) > 0) res.get(index).add(key);
                map.put(key, map.get(key) - 1);
            }
            index++;
        }
        return res;
    }
}

6364. 老鼠和奶酪

有两只老鼠和 n 块不同类型的奶酪,每块奶酪都只能被其中一只老鼠吃掉。

下标为 i 处的奶酪被吃掉的得分为:

  • 如果第一只老鼠吃掉,则得分为 reward1[i] 。
  • 如果第二只老鼠吃掉,则得分为 reward2[i] 。

给你一个正整数数组 reward1 ,一个正整数数组 reward2 ,和一个非负整数 k 。

请你返回第一只老鼠恰好吃掉 k 块奶酪的情况下,最大 得分为多少。

示例 1:

输入:reward1 = [1,1,3,4], reward2 = [4,4,1,1], k = 2
输出:15
解释:这个例子中,第一只老鼠吃掉第 2 和 3 块奶酪(下标从 0 开始),第二只老鼠吃掉第 0 和 1 块奶酪。
总得分为 4 + 4 + 3 + 4 = 15 。
15 是最高得分。

示例 2:

输入:reward1 = [1,1], reward2 = [1,1], k = 2
输出:2
解释:这个例子中,第一只老鼠吃掉第 0 和 1 块奶酪(下标从 0 开始),第二只老鼠不吃任何奶酪。
总得分为 1 + 1 = 2 。
2 是最高得分。

提示:

  • 1 <= n == reward1.length == reward2.length <= 105
  • 1 <= reward1[i], reward2[i] <= 1000
  • 0 <= k <= n

java回溯(会超时):

//回溯
class Solution {
    int res = Integer.MIN_VALUE;
    public int miceAndCheese(int[] reward1, int[] reward2, int k) {
        int n = reward1.length;
        boolean[] record = new boolean[n];
        Arrays.fill(record, false);
        backtrack(reward1, reward2, k, 0, record);
        return res;
    }
    private void backtrack(int[] reward1, int[] reward2, int k, int start, boolean[] record){
        int count = 0;
        for(boolean r : record){
            if(r) ++count;
        }
        if(count == k){
            int sum = 0;
            for(int i = 0; i < reward1.length; ++i){
                if(record[i]) sum += reward1[i];
                else sum += reward2[i];
            }
            res = Math.max(res, sum);
            return;
        }
        for(int i = start; i < reward1.length; ++i){
            record[i] = true;
            backtrack(reward1, reward2, k, i + 1, record);
            record[i] = false;
        }
    }
}

啊啊啊啊,怎么又超时了

//超时 547 / 564 个通过测试用例
class Solution {
    public int miceAndCheese(int[] reward1, int[] reward2, int k) {
        int n = reward1.length;
        int[] diff = new int[n];
        for(int i = 0; i < n; ++i){
            diff[i] = reward1[i] - reward2[i];
        }
        // 寻找diff最大的前k个值
        List<Integer> pre_k = new ArrayList<>();
        for(int i = 0; i < k; ++i){
            int m = Integer.MIN_VALUE;
            int index = -1, j = 0;
            for(; j < n; ++j){
                if(pre_k.contains(j)) continue;
                if(diff[j] > m){
                    index = j;
                    m = diff[j];
                }
            }
            pre_k.add(index);
        }
        int res = 0;
        for(int i = 0; i < n; ++i){
            if(pre_k.contains(i)) res += reward1[i];
            else res += reward2[i];
        }
        return res;
    }
}

利用优先队列寻找最大的前k个值还是超时了,麻木了

//552 / 564 个通过测试用例
class Solution {
    public int miceAndCheese(int[] reward1, int[] reward2, int k) {
        int n = reward1.length;
        // 寻找diff最大的前k个值
        List<Integer> pre_k = findTopKIndex(reward1, reward2, k);
        int res = 0;
        for(int i = 0; i < n; ++i){
            if(pre_k.contains(i)) res += reward1[i];
            else res += reward2[i];
        }
        return res;
    }
    private List<Integer> findTopKIndex(int[] reward1, int[] reward2, int k) {
        List<Integer> result = new ArrayList<>();
        if(k == 0) return result;
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, Comparator.comparingInt(i -> (reward1[i] - reward2[i])));
        for (int i = 0; i < reward1.length; i++) {
            if (pq.size() < k) {
                pq.offer(i);
            } else if (reward1[i] - reward2[i] > reward1[pq.peek()] - reward2[pq.peek()]) {
                pq.poll();
                pq.offer(i);
            }
        }
        while (!pq.isEmpty()) {
            result.add(pq.poll());
        }
        Collections.reverse(result);
        return result;
    }
}

然后换动态规划,又超内存了,我服了

class Solution {
    public int miceAndCheese(int[] reward1, int[] reward2, int k) {
        int n = reward1.length;
        if(k >= n){
            int sum = 0;
            for(int x: reward1) sum+= x;
            return sum;
        }
        if(k > n/2){
            return miceAndCheese(reward2, reward1, n - k);
        }
        // dp[i][j]表示索引[0,i],第一只老鼠恰好吃掉 j 块奶酪的情况下的最大得分
        int[][] dp = new int[n][k + 1];
        dp[0][0] = reward2[0];
        if(k > 0) dp[0][1] = reward1[0];
        for(int i = 1; i < n; ++i){
            dp[i][0] = dp[i - 1][0] + reward2[i];
        }
        for(int i = 1; i < n && i < k; ++i){
            dp[i][i + 1] = dp[i - 1][i] + reward1[i];
        }
        for(int i = 1; i < n; ++i){
            for(int j = 1; j <= i && j<= k; ++j){
                dp[i][j] = Math.max(dp[i - 1][j - 1] + reward1[i], dp[i - 1][j] + reward2[i]);
            }
        }
        return dp[n - 1][k];
    }
}

原来还可以先全部吃reward2,再把没吃到的补上,我终于通过看题解过了这道题,不容易

class Solution {
    public int miceAndCheese(int[] reward1, int[] reward2, int k) {
        int ans = 0, n = reward1.length;
        for(int i = 0; i < n; ++i){
            ans += reward2[i];
            reward1[i] -= reward2[i];
        }
        Arrays.sort(reward1);
        for(int i = n - k; i < n; ++i){
            ans += reward1[i];
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值