POJ 3320 Jessica‘s Reading Problem 尺取法

一、题目大意

给定一个长度为p的数组,其中可能包含重复元素,找到包含数组所有元素至少一次的连续最短序列长度

二、解题思路

我们可以使用尺取法定义左(left)右(right)两个指针,代表[left,right)为当前有效长度(左闭右开),按照如下思路进行尺取法

1、不断的移动right,直到right=p或者[left,right)中包含数组全部元素至少一次
2、如果right=p,但是[left,right)仍然不包含全部元素至少一次,退出程序
3、记录 result = min (result , res)
4、放大left

在获取输入的时候,可以使用set去重,然后set的大小len就是去重后的数量,可以使用map记录每个元素出现的个数,当right右移时,判断如果有元素右移之前是0变成1了,把sum+1,同时不管sun是否变化,都要更新map里的值,然后不断增大right,直到sum==len

当left右移动时,从map中拿到去掉的元素出现的次数,如果去掉之后这个元素出现了0次,那么sum-1,同时不管sum是否变化,一定要更新map

然后每次sum==len时,更新结果为min(result,right-left)

三、代码

#include 
#include 
#include 
using namespace std;
int arr[1000007], n = 0, len = 0, distinctArr[1000007], countArr[1000007], res;
map cntMap;
void input()
{
    scanf("%d", &n);
    res = n;
    set distinctSet;
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
        distinctSet.insert(arr[i]);
        cntMap[arr[i]] = 0;
    }
    len = distinctSet.size();
}
void solve()
{
    // 我们设置[left,right)为有效范围
    int left = 0, right = 0, sum = 0, cnt;
    while (left <= right)
    {
        while (right < n && sum < len)
        {
            cnt = cntMap[arr[right]];
            if (cnt == 0)
            {
                sum++;
            }
            cnt++;
            cntMap[arr[right++]] = cnt;
        }
        if (sum < len)
        {
            return;
        }
        res = min(res, right - left);
        cnt = cntMap[arr[left]];
        cnt--;
        if (cnt == 0)
        {
            sum--;
        }
        cntMap[arr[left++]] = cnt;
    }
}
int main()
{
    input();
    solve();
    printf("%d\n", res);
    return 0;
}

你可能感兴趣的:(算法,数据结构)