到手首先考虑暴力解法。也就是不管数组是否递增,只要相同的数字在一起出现就行,搜索一下头尾。
输出、循环等略,主循环内部核心逻辑如下:
--snip--
int head=-1,tail=-1
for (int index = 0; index < n; ++index)
{
if (array[index] == q_num)
{
if (head == -1)head = index;
tail = index;
}
}
--snip--
但是这题最后有一个卡数据上限的数据点,会超时。
简单二分优化一下:
--snip--
int begin = 0, end = n;
int mid = (begin + end) / 2;
while (array[mid] != q_num&&(end-begin)>10)
{
if (array[mid] < q_num)
begin = mid;
if (array[mid] > q_num)
end = mid;
mid = (begin + end) / 2;
}
for (int index = begin; index < end; ++index)
{
--snip--
}
--snip--
首先是用选择好的begin和end来代替原来的0和n,控制搜索的范围。
然后检测区间的中值,如果头尾恰好在两边那就不管了,反正也就这一个数据点,不影响大局。
然后循环更新。注意&&(end-begin)>10
这个循环条件,写宽一点也不碍事。
本来一开始是不想循环加速的,只要除了一个数据点之外别的速度都翻倍马马虎虎过了就行,没想到还是tle
(我称之为有限优化,这样可以有效减少错误的出现,慢点就慢点,不超时就完事儿了。)
全代码如下:
#include <iostream>
using namespace std;
int main()
{
int n, q;
cin >> n >> q;
int array[n];
for (auto& i:array)cin >> i;
for (int query = 0; query < q; ++query)
{
//input
int q_num;
cin >> q_num;
//smallen range of [begin,end)
int begin = 0, end = n;
int mid = (begin + end) >> 1;
while (array[mid] != q_num && (end - begin) > 10)
{
if (array[mid] < q_num)
begin = mid;
if (array[mid] > q_num)
end = mid;
mid = (begin + end) >> 1;
}
//search [begin,end)
int head = -1, tail = -1;
for (int index = begin; index < end; ++index)
{
if (array[index] == q_num)
{
if (head == -1)head = index;
tail = index;
}
}
//output
cout << head << " " << tail << endl;
}
return 0;
}
ps:循环条件的意思是,不要考虑多少的时候终止,随便胡诌一个不太大的数就行了。