P2249

刷题小记

校赛狙击失败&蓝桥杯国赛拿了国三。反思:对于一些简单的算法的细节却不是很到位,于是回过头来重刷。

P2249【深基13.例1】查找

二分查找,手撕的时候要注意的是:

#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 1000005;
int a[MAXN];
int b[MAXN];
int find(int front, int end, int num){
	//cout << "front: " << front << "end:" << end << endl;
	if(front == end || front + 1 == end) {
		if(a[front] == num) return front;
		if(a[end] == num) return end;
		return -1;
	}
	int mid = (front + end) / 2;
//	cout << front << end << ",";
	if(a[mid] < num) {
		return find( mid + 1, end, num);
	}else if(a[mid] > num) return find( front, mid - 1, num);
	else {
		int tmp = find( front, mid - 1, num);
		if(tmp == -1) return mid;
		return tmp;
	}
	return mid;
	
}



int main(void) {
	int n, m;
	cout.sync_with_stdio(false);
	cin.sync_with_stdio(false);
	cin >> n >> m;
	for(int i = 0; i < n; ++i) {
		
		cin >> a[i];
		
	}
	while(m--) {
		int tmp;
		cin >> tmp;
		int call = find(0, n - 1, tmp);
		if(call != -1)cout << call+1 << " ";
		else cout << call << " ";
	}
	
	
}
  1. 纯粹的二分查找之后没办法确定当前的数是最先出现的数。
  2. 为了解决1的问题,在==的时候加入了一个while(--)来判定,但当全部为一个数的时候,复杂度O(n),最后一个测试点tle了。
  3. 为了解决2的问题,想到了在==的时候继续进行二分查找(对左区间)。如果左区间没有(返回-1)的话,就返回当前mid值,否则就返回对左区间查找的结果。
  4. 在第3步对find()进行判定,然后再返回的时候,用一个临时变量tmp存下来,不然就会递归2次,后3个点直接tle。

模拟手撕完了,再试试stl——lower_bound()和upper_bound(),

#include <iostream>
using namespace std;
int a[1000005];

int main() {
	int n, m;
	cin >> n >> m;
	for(int i = 0; i < n; ++i) cin >> a[i];
	while(m--) {
		
		int query;
		cin >> query;
		int* result = lower_bound(a, a+n, query);
		if(*result == query) cout << result - a + 1<<" ";
		else cout << -1 <<" ";
		
		
	}
}

好家伙,年轻人不讲武德,用stl欺负我这个模拟撕了半个小时的人。3分钟就好了。

原文地址:https://www.cnblogs.com/ranbom/p/13982829.html