Tokitsukaze and Eliminate (hard) stl的 运用和贪心

思路:

通过审题,测试一组数据可以知道每次需要除去的数据是 每个数字 从左到右最后一次出现的坐标,且这个坐标在最左边(贪心)

O(N^2)作法,被TLE的做法:

#include <bits/stdc++.h>
using namespace std;
unordered_map<int, int> Hash;
const int N = 2e5 + 10;
struct A
{
    int appear;
    int number;
} number[N];
void solve()
{
    int n, ans = 0;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int a;
        cin >> a;
        number[i].number = a;
        number[i].appear = ++Hash[a];
    }
    int m = n;
    while (1)
    {
        for (int i = 1; i <= m; i++)
        {
            int N = number[i].number, A = number[i].appear;
            if (Hash[N] == A)
            {
                for (int j = i; j <= m; j++)
                {
                    int N = number[j].number;
                    Hash[N]--;
                }
                ans++;
                m = i - 1;
                break;
            }
        }
        if (m == 0)
            break;
    }
    cout << ans << endl;
}

用Hash表存储每个数字出现的次数,然后从头开始遍历,第一次满足: 该数在该点的出现次数=该数的出现次数,则满足去除的条件,然后从该点开始 在除去该点后面的坐标,继续更新。

TLE的原因:

因为每次去除掉一个点后,删除点的时候没有多余操作,因此都需要从头开始再遍历,时间复杂度为N^2,没利用删除点的信息。

O(N)做法:

用一个vector<int> number[N] 储存 每个数字出现的坐标,然后找到标号最小的第一次出现的坐标,将该坐标及其之后的坐标全部删除,删除的时候找到每个被删元素的 前一个元素的坐标,把这些坐标取最小值,那么就可以得到第二次坐标最小值(依次迭代)

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
vector<int> arr[N];
int A[N];
void solve()
{
    int n, ans = 0;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int a;
        cin >> a;
        A[i] = a;
        arr[a].push_back(i);
    }

    int Min = N;
    for (int i = 1; i <= n; i++)
    {
        if (arr[i].size())
            Min = min(Min, arr[i].back()); // 找到要删除的点的下标
    }
    int i = n; // 数字长度
    while (i >= 1)
    {

        int temp = Min;
        for (int j = temp; j <= i; j++)
        {
            arr[A[j]].pop_back();
            if (arr[A[j]].size())
                Min = min(Min, arr[A[j]].back()); // 删除后 再拿该点删除前的那个点
        }
        ans++;
        i = temp - 1;
    }
    cout << ans << endl;
}
// 解题的关键是找到每个数 最后一次出现 且在最左边的数据 那么我需要一个数据结构 存储每个数的出现次数,序号(最左边),
int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值