leetcode刷题日记-【2033. 获取单值网格的最小操作数】

92 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情

题目描述

给你一个大小为 m x n 的二维整数网格 grid 和一个整数 x 。每一次操作,你可以对 grid 中的任一元素 加 x 或 减 x 。

单值网格 是全部元素都相等的网格。

返回使网格化为单值网格所需的 最小 操作数。如果不能,返回 -1 。

示例 1:

image.png

输入:grid = [[2,4],[6,8]], x = 2 输出:4 解释:可以执行下述操作使所有元素都等于 4 :

  • 2 加 x 一次。
  • 6 减 x 一次。
  • 8 减 x 两次。 共计 4 次操作。 示例 2:

image.png

输入:grid = [[1,5],[2,3]], x = 1 输出:5 解释:可以使所有元素都等于 3 。 示例 3:

image.png

输入:grid = [[1,2],[3,4]], x = 2 输出:-1 解释:无法使所有元素相等。  

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 105
  • 1 <= m * n <= 105
  • 1 <= x, grid[i][j] <= 104

题目元素

  • 给定一个二维数组和一个正数x
  • 二维数组代表网格中的元素,正数x代表需要将网格中的元素进行+x或者-x,将它们变成一样的数字,求将它们变成相同数字需要进行最小的操作数。不能将它们全部变成相等的数的直接返回-1。

解题思路

假定数组中所有的元素最终都通过加减n倍x变成y,所以数组中的任意元素都可能是数字y,即数组中的任意元素都能通过其它元素通过加减x倍x得到。 在得知了这个的前提下,假设所有的元素总共操作n次变成y,每次操作的数量为x,总的操作距离为m,所以可以计算出元素的变化长度为nx=m,x是题目给定的可以说是固定值,那n和m就是变量,m和n是成正比关系,这里要求最小的n,则m一定是最有小的。

所以这道题也可以变成求数组中所有元素与y的距离最小时的y的值。可以将数组中的元素看成线段,y值其实就是在中间那条线段上,又由于数组中的所有元素都可以是y,所以可以直接取数组的中位数即是产生最小次数的y。 这里很多同学可能会纠结,当数组长度是奇数或者偶数是需要区分取数组中哪一个数,其实如上面解释所说,只要是数组中间那条线段上的值其实都满足最小,随便取一个都是满足条件的。

代码实现

/**
 * @param grid
 * @param x
 * @return
 */
public static int minOperations(int[][] grid, int x) {
    // 将所有元素放入新数组中
    int[] allItems = new int[grid.length * grid[0].length];
    int index = 0;
    for (int[] ints : grid) {
        for (int anInt : ints) {
            allItems[index] = anInt;
            index ++;
        }
    }
    // 排序
    Arrays.sort(allItems);
    // 取下标为中位数的数组值
    int y = allItems[allItems.length / 2];
    // 求操作次数
    int sum = 0;
    for (int allItem : allItems) {
        int distance = Math.abs(allItem - y);
        if (distance % x != 0) {
            return -1;
        }
        sum += distance/x;
    }
    return sum;
}