力扣-只出现一次的数字+CCF认证考试模拟练习两题

第六十三天 --- 力扣-只出现一次的数字+CCF认证考试模拟练习两题

题目一

在这里插入图片描述
在这里插入图片描述

解题思路

解释一下题目,就是统计各个可能的灰度值出现的次数。

代码

//202104-1	灰度直方图

#include <iostream>
#include <algorithm>
using namespace std;

int h[256];//提前把空间开够,有利于加速
int n, m, l;

int main()
{
	cin >> n >> m >> l;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {//边读入,边判断位置
			int temp = 0;
			scanf("%d", &temp);
			h[temp]++;
		}
	}
	int i = 0;
	for (; i < l - 1; i++) {
		printf("%d ", h[i]);
	}
	printf("%d", h[i]);
}

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述

时间复杂度:O(N^2)
空间复杂度:O(N),开了一个结果数组。

题目二:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

解题思路

按照题目中要求,就是遍历每一个点,计算邻域内部灰度平均值,与标准比较就行。

1、计算邻域

按照题目要求,其实就是以该点为中心向上下左右长度各为r的一个矩阵,那个就是本题目领域,但是注意不能越界,如果越界,要改变边界。

2、计算邻域内灰度和

1、试想,如果按照笨办法即用O(N^2)的速度计算每一个子矩阵灰度和,那么如果数据量大起来了,肯定会超时,并且看题目最后的数据约定,一旦他这么给了两段数据量,那么就必定会卡数据,所以一定要想到一种更好的解决计算灰度和方案。
2、回想数组,即一串数据,在O(1)的复杂度下求出区间和,很明显用前缀和,那么矩阵内部所有元素和,其实就是从原本的一维转换到了二维,所以仍然可以用前缀和快速球和,方法如下:
在这里插入图片描述
在这里插入图片描述

代码

//202104-2	邻域均值

#include <iostream>
#include <algorithm>
using namespace std;

int grey[601][601];//存储灰度矩阵
int n, l, r, t;
int ans = 0;

//要掌握在O(1)时间内求出来子矩阵的和---二维前缀和

int suming(int x1, int y1, int x2, int y2) {//计算灰度和
	return grey[x2][y2] - grey[x1 - 1][y2] - grey[x2][y1 - 1] + grey[x1 - 1][y1 - 1];
}

int adjust(int x) {//调整边界,防止越界
	if (x >= 1 && x <= n) {
		return x;
	}
	else {
		if (x < 1) {
			return 1;
		}
		else {
			return n;
		}
	}
}

int main()
{
	cin >> n >> l >> r >> t;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			int temp = 0;
			scanf("%d", &temp);
			grey[i][j] = grey[i][j - 1] + grey[i - 1][j] - grey[i - 1][j - 1] + temp;//数据预处理
		}
	}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			int x1 = i - r;//计算边界
			int x2 = i + r;
			int y1 = j - r;
			int y2 = j + r;
			x1 = adjust(x1);//调整边界
			x2 = adjust(x2);
			y1 = adjust(y1);
			y2 = adjust(y2);
			int all_points = (x2 - x1 + 1)*(y2 - y1 + 1);//计算总点数
			int sums = suming(x1, y1, x2, y2);//计算灰度和
			if (all_points*t >= sums) {//原题说平均值,计算机里面除法不计小数部分,所以除法转换成乘法
				ans++;
			}
		}
	}

	cout << ans;
}

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

时间复杂度:O(N^2)
空间复杂度:O(N^2)

题目三

在这里插入图片描述

注:

一定看好题目要求,他说了每个节点最多出现两次,所以要么单独出现,要么一对一对出现。

思路:

1、最简单的想法,利用unordered_set记录谁来了,如果第一次那么就写入set,反之就说明出现了多次,从set中删除,最后set剩下的就是答案,这个想法比较简单,这里略。
2、一旦出现了数组,进行有关数据技术比较,看是否重复出现等,一定要想到尝试位运算!!
其中,异或运算^ ,是重中之重,它能判断是否重复,他有三大特点:
1、a^a=0
2、a^0=a
3、a ^ b ^ c = a ^ c ^ b
再加之数据一对一对出现,所以只需要把全部数据异或起来,通过不断调位置,把成对出现的放在一起,最后就剩下单独的了。

代码:

class Solution {
public:
	int singleNumber(vector<int>& nums) {
		int ans = 0;
		for (int i = 0; i < nums.size(); i++) {
			ans ^= nums[i];
		}
		return ans;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JLU_LYM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值