Jessica's Reading Problem POJ - 3320 (尺取法)

Jessica’s a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The author of that text book, like other authors, is extremely fussy about the ideas, thus some ideas are covered more than once. Jessica think if she managed to read each idea at least once, she can pass the exam. She decides to read only one contiguous part of the book which contains all ideas covered by the entire book. And of course, the sub-book should be as thin as possible.

A very hard-working boy had manually indexed for her each page of Jessica’s text-book with what idea each page is about and thus made a big progress for his courtship. Here you come in to save your skin: given the index, help Jessica decide which contiguous part she should read. For convenience, each idea has been coded with an ID, which is a non-negative integer.

Input
The first line of input is an integer P (1 ≤ P ≤ 1000000), which is the number of pages of Jessica’s text-book. The second line contains P non-negative integers describing what idea each page is about. The first integer is what the first page is about, the second integer is what the second page is about, and so on. You may assume all integers that appear can fit well in the signed 32-bit integer type.

Output
Output one line: the number of pages of the shortest contiguous part of the book which contains all ideals covered in the book.

Sample Input
5
1 8 8 8 1
Sample Output
2

假设区间(l,r)满足条件,那么任何包含此区间的区间也必然满足条件,但不是最小区间,所以用尺取法比较合适
代码:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;

public class Main 
{

    public static void main(String[]args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int a[]=new int[n+1];
        HashSet set=new HashSet();
        HashMap map=new HashMap();//每个数字到出现次数的映射
        for(int i=1;i<=n;i++)
        {
            a[i]=sc.nextInt();
            set.add(a[i]);//首先用一个set来统计有多少个不同的元素
        }
        int total=set.size();//转到total
        set=null;//释放空间
        int l=1,r=1;
        int ans=n;
        map.put(a[1],1 );//初始化,动态维护相应区间的元素的个数以及每个元素出现的个数

        for(;;)
        {
            if(map.size()!=total)
            {
                if(r==n)
                    break;//终止条件
                else
                {
                    r++;
                    if(!map.containsKey(a[r]))
                        map.put(a[r],1);//如果不存在,就加入set
                    else
                        map.put(a[r],map.get(a[r])+1);反之在原来个数的基础上加一
                }
            }
            else
            {
                ans=Math.min(ans,r-l+1);//更新
                if(ans==total)//这个可以不写,如果区间宽度和主题的个数相等,那么就一定没有比这个更小的值了,出现这种情况的几率比较小
                    break;
                int num=map.get(a[l]);
                if(num>1)//因为要把区间左边右移,则需要知道被移除的元素之前出现的次数
                    map.put(a[l], num-1);//如果大于1,那么在原来的基础上减1,并不会改变map的size

                else
                    map.remove(a[l]);//反之size减1,
                l++;//右移
            }
        }
        System.out.println(ans);
    }
}

你可能感兴趣的:(算法分析,解题报告,尺取法)