题目描述:
有一条很长的队伍,队伍里面一共有n个人。所有的人分为三类:警察,小偷和普通人。
将队伍里面的人从前到后由1到n编号,编号为i的人与编号为j的人的距离为i与j之差的绝对值。
每一个警察有一个能力值x,表示他能够监视与他距离不超过x的所有人,
小偷被警察发现当且仅当他被一个或多个警察监视到。你知道在整条队伍中,一共有多少个小偷会被警察发现吗?
输入:
输入有两行,第一行一个数n(1<=n<=100000),接下来一行有一个长度为n的字符串,依次表示队伍中的每一个人。如果某一位是1-9的某个数字x,
表示这一位是一个能力值为x的警察;如果某一位是字符X表示这一位是小偷;如果某一位是字符#表示这是一个普通人。输入保证不会出现其它字符。
输出:
输出一个数,整条队伍中被警察发现的小偷总数。
样例输入:
9
X1X#2X#XX
样例输出:
3
思路:从头到尾扫描整个字符串,设置一个range变量表示当前位置的最大警力值,每扫描一个字符则range--,若当前字符代表小偷,则保存在thief容器里;若是警察,则更新当前的最大警力值range,然后从thief容器依次删除在该警力范围的小偷。最终遍历完这个字符串的时候,thief容器里保存了所有不能被警察抓到的小偷在字符串中的索引,由于只遍历了一次字符串,而thief容器最多只压入个索引,最多也只删除n个索引,所以时间复杂度仍然为O(n)。
#include <iostream>
#include <cmath>
#include <vector>
#include <stack>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
int main()
{
int n;
string str;
cin >> n >> str;
vector<int> thief; //记录小偷的位置
int range = -1; //记录警力在当前位置的能力值
int nb_thief = 0; //记录小偷的数量
for(int i = 0; i < str.size(); i++)
{
if(str[i] == 'X')
{
nb_thief++;
if (range < 0) thief.push_back(i);
}
else if(str[i] != '#')
{
int police = str[i] - '0';
range = max(range, police);
while(!thief.empty())
{
//在警力范围内,则删除
if(range >= i - thief.back())
thief.pop_back();
else break;
}
}
range--;//每次走一步,最大警力范围值-1
}
cout << nb_thief - thief.size() << endl;
}