6406. Maximum Sum With Exactly K Elements

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。你需要执行以下操作 恰好 k 次,最大化你的得分:

  1. 从 nums 中选择一个元素 m 。
  2. 将选中的元素 m 从数组中删除。
  3. 将新元素 m + 1 添加到数组中。
  4. 你的得分增加 m 。

请你返回执行以上操作恰好 k 次后的最大得分。

测试样例

输入:nums = [1,2,3,4,5], k = 3

输出:18

解释:我们需要从 nums 中恰好选择 3 个元素并最大化得分。第一次选择 5 。和为 5 ,nums = [1,2,3,4,6] 。第二次选择 6 。和为 6 ,nums = [1,2,3,4,7] 。第三次选择 7 。和为 5 + 6 + 7 = 18 ,nums = [1,2,3,4,8] 。所以我们返回 18 。18 是可以得到的最大答案。

解答:感觉这道题目就是在寻找最大值。。。

class Solution {
    public int maximizeSum(int[] nums, int k) {
        int max = 0;
        for (int i : nums) {
            max = Math.max(max, i);
        }
        int res = 0;
        for (int i = 0; i < k; ++i) {
            res += max;
            ++max;
        }
        return res;
    }
}

6405. Find the Prefix Common Array of Two Arrays

给你两个下标从 0 开始长度为 n 的整数排列 A 和 B 。

A 和 B 的 前缀公共数组 定义为数组 C ,其中 C[i] 是数组 A 和 B 到下标为 i 之前公共元素的数目。

请你返回 A 和 B 的 前缀公共数组 。

如果一个长度为 n 的数组包含 1 到 n 的元素恰好一次,我们称这个数组是一个长度为 n 的 排列 。

测试样例:

输入:A = [1,3,2,4], B = [3,1,2,4]

输出:[0,2,3,4]

解释:

  • i = 0:没有公共元素,所以 C[0] = 0 。
  • i = 1:1 和 3 是两个数组的前缀公共元素,所以 C[1] = 2 。
  • i = 2:1,2 和 3 是两个数组的前缀公共元素,所以 C[2] = 3 。
  • i = 3:1,2,3 和 4 是两个数组的前缀公共元素,所以 C[3] = 4 。

解答: 这道题目范围:1 <= A.length == B.length == n <= 50。这个范围相当小,直接暴力遍历就行了

class Solution {
    public int[] findThePrefixCommonArray(int[] A, int[] B) {
        int len = A.length;
        int[] res = new int[len];
        HashMap<Integer, Integer> left = new HashMap<>(), right = new HashMap<>();
        for (int i = 0; i < len; ++i) {
            left.put(A[i], left.getOrDefault(A[i], 0) + 1);
            right.put(B[i], right.getOrDefault(B[i], 0) + 1);
            for (Map.Entry<Integer, Integer> kv : left.entrySet()) {
                res[i] += Math.min(kv.getValue(), right.getOrDefault(kv.getKey(), 0));
            }
        }
        return res;
    }
}

6403. Maximum Number of Fish in a Grid

给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid ,其中下标在 (r, c) 处的整数表示:

  • 如果 grid[r][c] = 0 ,那么它是一块 陆地 。
  • 如果 grid[r][c] > 0 ,那么它是一块 水域 ,且包含 grid[r][c] 条鱼。

一位渔夫可以从任意 水域 格子 (r, c) 出发,然后执行以下操作任意次:

  • 捕捞格子 (r, c) 处所有的鱼,或者
  • 移动到相邻的 水域 格子。

请你返回渔夫最优策略下, 最多 可以捕捞多少条鱼。如果没有水域格子,请你返回 0 。

格子 (r, c) 相邻 的格子为 (r, c + 1) ,(r, c - 1) ,(r + 1, c) 和 (r - 1, c) ,前提是相邻格子在网格图内。

测试样例:

输入:grid = [[0,2,1,0],[4,0,0,3],[1,0,0,4],[0,3,2,0]]

输出:7

解答: 这道题目的范围也相当小。可以暴力BFS遍历或者用并查集寻找最大可联通的水域和水域对应能捕捉到的鱼。

class Solution {
    private class DSU{
        int[] parent;

        public DSU(int N) {
            parent = new int[N];
            for (int i = 0; i < N; ++i) {
                parent[i] = i;
            }
        }

        public int find(int x) {
            if (parent[x] != x) parent[x] = find(parent[x]);
            return parent[x];
        }

        public void union(int x, int y) {
            parent[find(x)] = find(y);
        }
    }

    private static final int[] moves = {1,0,-1,0,1};

    public int findMaxFish(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        DSU uf = new DSU(m * n);
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] != 0) {
                  for (int k = 0; k < 4; ++k) {
                      int xt = i + moves[k], yt = j + moves[k + 1];
                      if (xt >= 0 && xt < m && yt >= 0 && yt < n && grid[xt][yt] != 0) {
                          uf.union(xt * n + yt, i * n + j);
                      }
                  }
                }
            }
        }
        int res = 0;
        HashMap<Integer, Integer> mem = new HashMap<>();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] != 0) {
                    int key = uf.find(i * n + j);
                    int total = mem.getOrDefault(key, 0) + grid[i][j];
                    res = Math.max(res, total);
                    mem.put(key, total);
                }
            }
        }
        return res;
    }
}

6404. Make Array Empty

给你一个包含若干 互不相同 整数的数组 nums ,你需要执行以下操作 直到数组为空 :

  • 如果数组中第一个元素是当前数组中的 最小值 ,则删除它。
  • 否则,将第一个元素移动到数组的 末尾 。

请你返回需要多少个操作使 nums 为空。

测试样例:

输入:nums = [3,4,-1]

输出:5

解答:这道题目,首先考的是排序,利用排序可以知道当前位置和下一个位置。然后按照题意,如果元素满足会被移除,所以需要了解当前位置和下一个位置之间还存在的元素数。这个利用树状态数组可以轻松计算。有这两部分的准备,就可以直接计算了。

class Solution {
    class SegmentTree {
        int[] tree;
        int n;
        public SegmentTree(int len) {
            n = len;
            tree = new int[n * 2];

            for (int i = n, j = 0;  i < 2 * n; i++,  j++)
                tree[i] = 1;
            for (int i = n - 1; i > 0; --i)
                tree[i] = tree[i * 2] + tree[i * 2 + 1];
        }

        void update(int pos, int val) {
            pos += n;
            tree[pos] = val;
            while (pos > 0) {
                int left = pos;
                int right = pos;
                if (pos % 2 == 0) {
                    right = pos + 1;
                } else {
                    left = pos - 1;
                }
                // parent is updated after child is updated
                tree[pos / 2] = tree[left] + tree[right];
                pos /= 2;
            }
        }

        public int sumRange(int l, int r) {
            // get leaf with value 'l'
            l += n;
            // get leaf with value 'r'
            r += n;
            int sum = 0;
            while (l <= r) {
                if ((l % 2) == 1) {
                    sum += tree[l];
                    l++;
                }
                if ((r % 2) == 0) {
                    sum += tree[r];
                    r--;
                }
                l /= 2;
                r /= 2;
            }
            return sum;
        }
    }

    public long countOperationsToEmptyArray(int[] nums) {
        int len = nums.length;
        Integer[] sort = new Integer[len];
        for (int i = 0; i < sort.length; ++i) {
            sort[i] = i;
        }
        Arrays.sort(sort, (a, b) -> (nums[a] - nums[b]));
        SegmentTree tree = new SegmentTree(len);
        int cur = 0;
        long res = 0;
        for (int s : sort) {
            if (s >= cur) {
                res += tree.sumRange(cur, s);
            } else {
                res = res + tree.sumRange(cur, len - 1) + tree.sumRange(0, s);
            }
            tree.update(s, 0);
            cur = (s + 1) % len;
        }
        return res;
    }
}

今年第一次,在究极手速场中获得不错的排名。还有,祝大家五一节快乐!

Leave a Reply

Your email address will not be published. Required fields are marked *