第六十六天 --- 力扣-240+CCF两题
题目一
思路
这个题目看起来很简单,最暴力的解法无非就是访问矩阵的每一个点即可,但这效率不高,所以在提及检索的时候,我们第一个想到的就是二分检索(一维),所以我们从这里出发,一起看本题要用什么方法。
方法一:一个维度的二分检索,另一个维度顺序
1、这个是我自己想的思路,很简单,二维矩阵的每一行都是一个一维数组,那么我们可不可以简化每一行的检索过程,即每一行上进行快速的二分检索,这一行没有就进入下一行,这样就可以找到答案。
2、值得注意的是,当进入新的一行的时候,发现行首的值大于目标值,根据题意可知,从该行起,他的下面所有元素都大于目标,就没必要找了,减少搜索过程。
方法二:二维二分查找
二维最大的特点就是,有两个维度,所以二分找的时候不能只找一个维度,必须找一次,搜索两个维度,为了做到这点,其实也很简单,只需要沿着对角线搜索就行。
过程如上图所示,按照对角线搜索即可,但也如图所示,会产生很多冗余查找,所以时间复杂度较高。
方法三:线性复杂度查找
以上方法其实都没充分用到本体的关键性条件,即每行从左到右递增,每列从上到下递减。
1、首先要明白这个矩阵里的每个元素其实都是有序的
2、第二,我们要找到边界关键点,即他在边界且可进可退,如果目标大于或者小于这个节点,那么都得能找出相应的移动方向,所以关键点初始点只能是左下角,右上角
3、从关键点走,以左下角为例,小于关键点,则关键点就往上走,反之向右走,直到找到目标或者向上向右越界
代码
方法一代码:
注:在使用vector或者数组的时候,一定注意,他的有效范围在0~n-1,千万别越界。
class Solution {
public:
bool binaryFind(int target, vector<int>& item) {
//二分查找,不做赘述
int i = 0, j = item.size() - 1;
while (i <= j) {
int mid = (i + j) / 2;
if (item[mid] == target) {
return true;
}
else if(item[mid] > target){
j = mid - 1;
}
else if (item[mid] < target) {
i = mid + 1;
}
}
return false;
}
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
if (target<matrix[0][0] || target>matrix[m - 1][n - 1]) {
//把很明显不对的数据排除
return false;
}
if (target == matrix[0][0] || target == matrix[m - 1][n - 1]) {
return true;
}
for (int i = 0; i < matrix.size(); i++) {
//枚举行
if (matrix[i][0] > target) {
break;
}
if (binaryFind(target, matrix[i])) {
return true;
}
}
return false;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(nlgn)
空间复杂度:O(1)
方法二代码:
class Solution {
public:
int m, n;
bool binaryFind(vector<vector<int>>& matrix, int target, int p, bool col_or_row) {
//二维二分查找
int i = 0;
int j = col_or_row ? m - 1 : n - 1;//为真查列,为假查行
if (col_or_row) {
//col_or_row决定查列还是行
while (i <= j) {
//二分查列
int mid = (i + j) / 2;
if (matrix[mid][p] == target) {
return true;
}
else if (matrix[mid][p] > target) {
j = mid - 1;
}
else if (matrix[mid][p] < target) {
i = mid + 1;
}
}
}
else {
while (i <= j) {
//二分查行
int mid = (i + j) / 2;
if (matrix[p][mid] == target) {
return true;
}
else if (matrix[p][mid] > target) {
j = mid - 1;
}
else if (matrix[p][mid] < target) {
i = mid + 1;
}
}
}
return false;
}
bool searchMatrix(vector<vector<int>>& matrix, int target) {
m = matrix.size();
n = matrix[0].size();
if (matrix.empty() || matrix[0].empty()) {
//处理特殊情况,为空,两种空的情况
return false;
}
if (target<matrix[0][0] || target>matrix[m - 1][n - 1]) {
//排除肯定错的
return false;
}
if (target == matrix[0][0] || target == matrix[m - 1][n - 1]) {
return true;
}
int shorterDim = min(matrix.size(), matrix[0].size());//找对角线
for (int i = 0; i < shorterDim; i++) {
//按照对角线找点
bool find1 = binaryFind(matrix, target, i, true);//扫列
bool find2 = binaryFind(matrix, target, i, false);//扫行
if (find1 || find2) {
return true;
}
}
return false;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
方法三代码:
1、左下角
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size() - 1, n = 0;//初始值
while (m >= 0 && n < matrix[0].size()) {
//越界条件
if (matrix[m][n] > target) {
m--;
}
else if (matrix[m][n] < target) {
n++;
}
else {
return true;
}
}
return false;
}
};
2、右上角
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = 0, n = matrix[0].size() - 1;
while (m < matrix.size() && n >= 0) {
if (matrix[m][n] > target) {
n--;
}
else if (matrix[m][n] < target) {
m++;
}
else {
return true;
}
}
return false;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
题目二:
思路
直接模拟题目要求,注意输出的时候一定要换行
代码
///202006-1 线性分类器
#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;
int n, m;
int t0, t1, t2;
struct point {
//点
int x;
int y;
};
point p_A[1005], p_B[1005];//AB类型的点
int main()
{
cin >> n >> m;
int cnt_A = 0, cnt_B = 0;//AB类点的个数
for (int i = 0; i < n; i++) {
int tmp_x, tmp_y;
char tmp_c;
scanf("%d %d %c", &tmp_x, &tmp_y, &tmp_c);//输入
if (tmp_c == 'A') {
//输入
p_A[cnt_A].x = tmp_x;
p_A[cnt_A].y = tmp_y;
cnt_A++;
}
else {
p_B[cnt_B].x = tmp_x;
p_B[cnt_B].y = tmp_y;
cnt_B++;
}
}
for (int i = 0; i < m; i++) {
//开始处理不同直线
cin >> t0 >> t1 >> t2;
int change = -1;
bool fal = false;
for (int j = 0; j < cnt_A; j++) {
//处理A类点
int tmp = p_A[j].x*t1 + p_A[j].y*t2;
if (j == 0) {
//第一个点决定所有的点与直线的相对位置
if (tmp + t0 < 0) {
change = -1;
}
else {
change = 1;
}
}
else {
if( (tmp + t0 < 0&&change==1) || (tmp + t0 > 0 && change == -1)){
fal = true;//因为出现了在直线不同位置的点,代表A类点出现在直线两侧
break;
}
}
}
if (!fal) {
//处理B类点
for (int j = 0; j < cnt_B; j++) {
//含义同上
int tmp = p_B[j].x*t1 + p_B[j].y*t2;
if (j == 0) {
if (tmp + t0 < 0) {
change = -1;
}
else {
change = 1;
}
}
else {
if ((tmp + t0 < 0 && change == 1) || (tmp + t0 > 0 && change == -1)) {
fal = true;
break;
}
}
}
}
if (fal) {
printf("%s\n", "No");
}
else {
printf("%s\n", "Yes");
}
}
}
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N^2)
题目三
思路:
这个题其实思路很简单,但是需要处理好大数据的问题,所以基础思路就是哈希。思路就是以一个向量作为主体,第二个向量边读取,边查找第一个向量想同纬度的值。
代码:
注意:为了防止越界,一定要用long long,做题之前看好数据规模约定!!!!!!
//202006-2 稀疏向量
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
long long n, a, b;
int main()
{
cin >> n >> a >> b;
long long ans = 0;
unordered_map<long long, long long> item;//哈希实现的map
for (long long i = 0; i < a; i++) {
long long x, y;
scanf("%lld%lld", &x, &y);
item.insert(pair<long long, long long>(x, y));//添加map
}
for (long long i = 0; i < b; i++) {
long long x, y;
scanf("%lld%lld", &x, &y);
if (item.count(x) == 0) {
//同纬度没查到,则意味着同纬度下第一个向量的值为0
continue;
}
else {
ans += item.at(x)*y;
}
}
cout << ans;
}
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N)