携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情
题目描述
给你一个大小为 m x n 的二维整数网格 grid 和一个整数 x 。每一次操作,你可以对 grid 中的任一元素 加 x 或 减 x 。
单值网格 是全部元素都相等的网格。
返回使网格化为单值网格所需的 最小 操作数。如果不能,返回 -1 。
示例 1:
输入:grid = [[2,4],[6,8]], x = 2 输出:4 解释:可以执行下述操作使所有元素都等于 4 :
- 2 加 x 一次。
- 6 减 x 一次。
- 8 减 x 两次。 共计 4 次操作。 示例 2:
输入:grid = [[1,5],[2,3]], x = 1 输出:5 解释:可以使所有元素都等于 3 。 示例 3:
输入: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;
}