力扣262周赛-5895+5894

第七十九天 --- 力扣262周赛-5895+5894

题目一

力扣: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)

おすすめ

転載: blog.csdn.net/qq_45678698/article/details/120687522