题目一
解题思路
解释一下题目,就是统计各个可能的灰度值出现的次数。
代码
//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;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):