人物相关性分析 C++代码 分析 二分

题目总结:二分求[x-n,x+n]区间 和 求字串

两个考点:

  1. 如何求某子串在字符串中的位置集合
  2. 如何高效判断两个集合中的所有数的,绝对值之差小于某一个数

求子串的位置:

由于我们要求Alice和Bob的位置,而字符串中两个合法的单词是:在两个标点符号之间的串

所以求出所有的合法单词,再判断是不是Alice或者Bob

    string temp = "";
    for (int i = 0; i < n; i++)
    {
        // 如果s[i]是符号 那么s[i-1]之前的就是一个单词
        // 或许会有第一个字符就是标点符号,但没有关系,if中又判断了内容
        if (!isalpha(s[i]))
        {
            if (temp == "Alice")
                va.push_back(i - temp.size() + 1);
            else if (temp == "Bob")
                vb.push_back(i - temp.size() + 1);
            // 注意每次清空
            temp = "";
        }
        else  // 说明当前单词还没扫描完 继续完善单词
            temp += s[i];
    }

TLE的朴素算法 O ( N 2 ) O(N^2) O(N2)

	 for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
        {
            if (va[i] < vb[j] && (vb[j] - (va[i] + 4) - 1 <= K))
                ans++;
            if ((va[i] > vb[j]) && (va[i] - (vb[j] + 2) - 1 <= K))
                ans++;
        }

高效算法 二分 O ( N l o g N ) O(NlogN) O(NlogN)

遍历全部的Alice的位置,若Alice当前位置为x

则二分寻找Bob的位置集合中,符合条件的区间

分别二分左端点和右端点

有边界问题:

扫描二维码关注公众号,回复: 13133630 查看本文章

二分左的时候:如果Bob的位置没有比x小的,那么左端点的结果应该是比x大的第一个 那么这样也不矛盾

二分右的时候:如果Bob的位置没有比x大的,那么右端点的结果应该是比x小的第一个 这样也是右端点 不矛盾

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main()
{
    int K;
    string s;
    cin >> K;
    cin.get(); // 接收空字符
    getline(cin, s);

    vector<int> va, vb;
    s += '.';
    // 由于下面的切分是分别符号来的 所以最后可能不是符号结尾,即:******Alice 这种情况
    int n = s.size();
    // 单个单词
    string temp = "";
    for (int i = 0; i < n; i++)
    {
        // 如果s[i]是符号 那么s[i-1]之前的就是一个单词
        if (!isalpha(s[i]))
        {
            if (temp == "Alice")
                va.push_back(i - temp.size() + 1);
            else if (temp == "Bob")
                vb.push_back(i - temp.size() + 1);
            // 注意每次清空
            temp = "";
        }
        else
            temp += s[i];
    }
    // 二分求区间
    n = va.size();
    int m = vb.size();
    long long ans = 0;

    for (int i = 0; i < n; i++)
    {
        int l = 0, r = m - 1;
        while (l < r)
        {
            int mid = l + r >> 1;
            if (va[i] - (vb[mid] + 2) - 1 <= K)
                r = mid;
            else
                l = mid + 1;
        }
        int ansl = l;
        // 注意 再acwing上不加这个是可以过的
        // y总应该少考虑一个情况:有合法的Alice和Bob可是没有“同时出现”的
        // 意思是看找到的区间的左边界是否符合 如果不符合就是没有找到左边界
        if (va[i] - (vb[ansl] + 2) - 1 > K)
            continue;
        l = 0, r = m - 1;
        while (l < r)
        {
            // cout << l << " * " << r << endl;
            int mid = l + r + 1 >> 1;
            if (vb[mid] - (va[i] + 4) - 1 <= K)
                l = mid;
            else
                r = mid - 1;
        }
        // 同上
        if (vb[l] - (va[i] + 4) - 1 > K)
            continue;
        ans += (r - ansl + 1);
        // cout << ansl << ' ' << r   << endl;
    }
    cout << ans;
    cout << endl;

    // 调试使用
    // for(auto e: va)
    //     cout << e << " ";
    // cout << endl;
    // for(auto e: vb)
    //     cout  << e<< " ";
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45653525/article/details/114702244