欢迎大家加QQ群:623375442,可以方便群里面交流。

100342. Minimum Average of Smallest and Largest Elements

你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums,其中 n 为偶数。

你需要重复以下步骤 n / 2 次:

  • 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement。
  • 将 (minElement + maxElement) / 2 加入到 averages 中。

返回 averages 中的 最小 元素。

测试样例:

输入:nums = [7,8,3,4,15,13,4,1]

输出:5.5

解释:返回 averages 中最小的元素,即 5.5。

解答:排序后按照题意,配合指针来计算当前average,并记录最小值。

class Solution {
    public double minimumAverage(int[] nums) {
        Arrays.sort(nums);
        int st = 0, ed = nums.length - 1;
        double res = (nums[0] + nums[nums.length - 1]) / 2.0;
        while (st < ed) {
            res = Math.min(res, (nums[st] + nums[ed]) / 2.0);
            ++st;
            --ed;
        }
        return res;
    }
}

100334. Find the Minimum Area to Cover All Ones I

给你一个二维 二进制 数组 grid。请你找出一个边在水平方向和竖直方向上、面积 最小 的矩形,并且满足 grid 中所有的 1 都在矩形的内部。

返回这个矩形可能的 最小 面积。

测试样例:

输入:grid = [[0,1,0],[1,0,1]]

输出:6

解释:这个最小矩形的高度为 2,宽度为 3,因此面积为 2 * 3 = 6。

解答:遍历整个grid,寻找所有为1的节点的,最小x,y坐标和最大x,y坐标,然后计算所需要的面积。

class Solution {
    public int minimumArea(int[][] grid) {
        int[] nums = {0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE};
        for (int i = 0; i < grid.length; ++i) {
            for (int j = 0; j < grid[i].length; ++j) {
                if (grid[i][j] == 1) {
                    nums[0] = Math.max(i, nums[0]);
                    nums[1] = Math.min(i, nums[1]);
                    nums[2] = Math.max(j, nums[2]);
                    nums[3] = Math.min(j, nums[3]);
                }
            }
        }
        return (nums[0] - nums[1] + 1) * (nums[2] - nums[3] + 1);
    }
}

100337. Maximize Total Cost of Alternating Subarrays

给你一个长度为 n 的整数数组 nums。

子数组 nums[l..r](其中 0 <= l <= r < n)的 成本 定义为:

cost(l, r) = nums[l] - nums[l + 1] + ... + nums[r] * (−1)r − l

你的任务是将 nums 分割成若干子数组,使得所有子数组的成本之和 最大化,并确保每个元素 正好 属于一个子数组。

具体来说,如果 nums 被分割成 k 个子数组,且分割点为索引 i1, i2, ..., ik − 1(其中 0 <= i1 < i2 < ... < ik - 1 < n - 1),则总成本为:

cost(0, i1) + cost(i1 + 1, i2) + ... + cost(ik − 1 + 1, n − 1)

返回在最优分割方式下的子数组成本之和的最大值。

注意:如果 nums 没有被分割,即 k = 1,则总成本即为 cost(0, n - 1)。

测试样例:

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

输出:10

解释:一种总成本最大化的方法是将 [1, -2, 3, 4] 分割成子数组 [1, -2, 3] 和 [4]。总成本为 (1 + 2 + 3) + 4 = 10。

解答:这题可以利用动态规划。我们将每个位置记录两种状态,一种是它是1,另一种是-1。这两种状态的转移方程就比较简单了。-1的状态必然是从上一个1的状态转移过来。1的状态稍微复杂一点,它可以单独成一个子数组,也能从上一个-1继承过来。

class Solution {
    public long maximumTotalCost(int[] nums) {
        int len = nums.length;
        long[][] mem = new long[len][2];
        for (int i = 0; i < len; ++i) {
            mem[i][0] = Long.MIN_VALUE;
            mem[i][1] = Long.MIN_VALUE;
        }
        mem[0][0] = nums[0];
        for (int i = 1; i < len; ++i) {
            // 从上一个*-1继承过来
            mem[i][1] = -nums[i] + mem[i - 1][0];
            // 从上一个*1继承过来(当前位置切分一个新的子数组),或者从上一个*-1继承过来。
            mem[i][0] = Math.max(mem[i - 1][0], mem[i - 1][1]) + nums[i];
        }
        return Math.max(mem[len - 1][0], mem[len - 1][1]);
    }
}

100334. Find the Minimum Area to Cover All Ones I

给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形,并且满足 grid 中所有的 1 都在这些矩形的内部。

返回这些矩形面积之和的 最小 可能值。

注意,这些矩形可以相接。

测试样例:

输入:grid = [[1,0,1],[1,1,1]]

输出:5

解释:

  • 位于 (0, 0) 和 (1, 0) 的 1 被一个面积为 2 的矩形覆盖。
  • 位于 (0, 2) 和 (1, 2) 的 1 被一个面积为 2 的矩形覆盖。
  • 位于 (1, 1) 的 1 被一个面积为 1 的矩形覆盖。

解答:这题范围太小了,实际可以利用暴力计算。因为切分的3个长方形,它第一刀必然是横切 或者 竖切。然后又在切分完的两块中,寻找一块再切分,另一块就类似这周第二题寻找最小面积。

class Solution {
    private int m, n;

    public int minimumSum(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        List<int[]> list = new ArrayList<>();
        for (int i = 0; i < grid.length; ++i) {
            for (int j = 0; j < grid[i].length; ++j) {
                if (grid[i][j] == 1) {
                    list.add(new int[]{i, j});
                }
            }
        }

        int res = Integer.MAX_VALUE;
        // 横切
        for (int i = 0; i < m; ++i) {
            List<int[]> left = new ArrayList<>(), right = new ArrayList<>();
            for (int[] t : list) {
                if (t[0] <= i) {
                    left.add(t);
                } else {
                    right.add(t);
                }
            }
            {
                // 左边再切分,右边单块
                int l1 = findBestTwo(left), l2 = findBestOne(right);
                if (l1 != Integer.MAX_VALUE && l2 != Integer.MAX_VALUE) {
                    res = Math.min(l1 + l2, res);
                }
            }
            {
                // 右边再切分,左边单块
                int l1 = findBestTwo(right), l2 = findBestOne(left);
                if (l1 != Integer.MAX_VALUE && l2 != Integer.MAX_VALUE) {
                    res = Math.min(l1 + l2, res);
                }
            }
        }

        // 竖切
        for (int i = 0; i < n; ++i) {
            List<int[]> left = new ArrayList<>(), right = new ArrayList<>();
            for (int[] t : list) {
                if (t[1] <= i) {
                    left.add(t);
                } else {
                    right.add(t);
                }
            }
            {
                int l1 = findBestTwo(left), l2 = findBestOne(right);
                if (l1 != Integer.MAX_VALUE && l2 != Integer.MAX_VALUE) {
                    res = Math.min(l1 + l2, res);
                }
            }
            {
                int l1 = findBestTwo(right), l2 = findBestOne(left);
                if (l1 != Integer.MAX_VALUE && l2 != Integer.MAX_VALUE) {
                    res = Math.min(l1 + l2, res);
                }
            }
        }
        return res;
    }

    // 迭代暴力,直接横切和竖切再尝试一下最小面积
    private int findBestTwo(List<int[]> list) {
        if (list.size() <= 1) return Integer.MAX_VALUE;
        int res = Integer.MAX_VALUE;
        {
            for (int i = 0; i < m; ++i) {
                int[] n1 = initialArr(), n2 = initialArr();
                for (int[] t : list) {
                    if (t[0] <= i) {
                        update(t, n1);
                    } else {
                        update(t, n2);
                    }
                }
                if (n1[1] != Integer.MAX_VALUE && n2[1] != Integer.MAX_VALUE) {
                    res = Math.min(res, cal(n1) + cal(n2));
                }
            }
        }
        {
            for (int i = 0; i < n; ++i) {
                int[] n1 = initialArr(), n2 = initialArr();
                for (int[] t : list) {
                    if (t[1] <= i) {
                        update(t, n1);
                    } else {
                        update(t, n2);
                    }
                }
                if (n1[1] != Integer.MAX_VALUE && n2[1] != Integer.MAX_VALUE) {
                    res = Math.min(res, cal(n1) + cal(n2));
                }
            }
        }
        return res;
    }

    // 和本周第二题一致,寻找最小面积。
    private int findBestOne(List<int[]> grid) {
        if (grid == null || grid.isEmpty()) return Integer.MAX_VALUE;
        int[] nums = initialArr();
        for (int[] l : grid) {
            update(l, nums);
        }
        return cal(nums);
    }

    private void update(int[] l, int[] nums) {
        int i = l[0], j = l[1];
        nums[0] = Math.max(i, nums[0]);
        nums[1] = Math.min(i, nums[1]);
        nums[2] = Math.max(j, nums[2]);
        nums[3] = Math.min(j, nums[3]);
    }

    private int[] initialArr() {
        int[] nums = {0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE};
        return nums;
    }

    private int cal(int[] nums) {
        return (nums[0] - nums[1] + 1) * (nums[2] - nums[3] + 1);
    }
}

Leave a Reply

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