题目一
力扣:5895
思路
这里介绍一个思考问题办法:分块思考
1、我们就假设按照某一个值item来统一这个大矩阵,因为要统一每一个值,所以必须遍历所有值,所以用二维循环即可。针对每一个值,abs(grid[i][j]- item)%x==0,说明经过有限次加或者减可转化,反之不可转化(要使任意两元素最终相等,这两元素的差必须是 x 的倍数,否则无法通过加减 x 来相等),abs(grid[i][j]- item)/x就是转化次数,这两个公式用数学方法即可验证,这里略。
2、那么这个分功能设计好了,我们就得思考,怎么找到这个基准数item,来让整个数组转化时候步数最少。因为二维数组对数据分析较麻烦,所以我们二维化一维,数据混乱不利于我们分析,所以对之排序重整数组。
3、假设要让所有元素均为 ,设小于 y 的元素有 p 个,大于 y 的元素有 q 个,可以发现:
<1> 若 p<q,y 每增加 x,操作数就可以减小 q-p;
<2> 若 p>q,y 每减小 x,操作数就可以减小 p-q;
因此 p=qp=q 时可以让总操作数最小,此时 y 为所有元素的中位数。
4、“3”是数学证明,其实用通俗的话来讲,如果你把item选在边缘,选在两端(最大或者最小),那么在另一端的数转化的时候就会走很多步。那么问题来了,我们就要找一个平衡点,即让他左侧离他尽可能进,右侧也是,只有中点符合。
5、综上,这就是贪心法求解 item 的过程
代码
class Solution {
public:
int ans = INT_MAX;//初始化
vector<vector<int>> grid;
int item;//基准数
int x;//看题目
int m, n;//行列
void cntChangeTimes() {
//转化函数,功能在上
int tmp_ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int tmp = grid[i][j];
if (abs(tmp - item) % x == 0) {
tmp_ans += abs(tmp - item) / x;
}
else {
return;
}
}
}
ans = min(ans, tmp_ans);
}
int minOperations(vector<vector<int>>& grid, int x) {
this->x = x;//初始化
this->grid = grid;
m = grid.size();
n = grid[0].size();
vector<int> ano;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
ano.push_back(grid[i][j]);//二维转一维
}
}
sort(ano.begin(), ano.end());//排序重整
int n2 = ano.size();
item = ano[n2 / 2];//取中位数
cntChangeTimes();
if (ans == INT_MAX) {
return -1;
}
else {
return ans;
}
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(MN),M为矩阵的行,N为矩阵的列
题目二
思路
直接模拟即可,统计每个数字出现的次数,但一定要注意,一个数组,一种数只能出现一次,这样,出现的次数也同样是出现在多少个数组的个数。
代码
class Solution {
public:
vector<int> twoOutOfThree(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3) {
int cnt[101] = {
};//统计个数
vector<int> ans;
int n1 = nums1.size();
int n2 = nums2.size();
int n3 = nums3.size();
unordered_set<int> tmp1;//用于防止相同的数字出现多次
for (int i = 0; i < n1; i++) {
if (!tmp1.count(nums1[i])) {
cnt[nums1[i]]++;
tmp1.insert(nums1[i]);
}
}
unordered_set<int> tmp2;
for (int i = 0; i < n2; i++) {
if (!tmp2.count(nums2[i])) {
//这个数没出现过,再将之++
cnt[nums2[i]]++;
tmp2.insert(nums2[i]);
}
}
unordered_set<int> tmp3;
for (int i = 0; i < n3; i++) {
if (!tmp3.count(nums3[i])) {
cnt[nums3[i]]++;
tmp3.insert(nums3[i]);
}
}
for (int i = 0; i < 101; i++) {
if (cnt[i] >= 2) {
ans.push_back(i);
}
}
return ans;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N)