• 子序列(续集) (Data_Structure)


           这个题,我用map做的,后来验证是错误的,算法错了。比如这组数据:

    18

    1 2 2 3 3 4 4 1 2 3 4 1 2 2 3 3 4 4

    我的代码得出6,但是正确答案是4.

            我是统计每个数出现了多少次,然后从左往右,碰到相同的次数减1,谁刚好到1了(如果大于1,说明右边会存在相同的数)就停下,得出位置first,再从右往左,类似操作,得出end,从first到end之间必然会包括序列中的所有数。但是满足这个条件的子序列不一定是最短的。比如我的算法,会得出的子序列是后面的1 2 2 3 3 4,但是最短的是中间的1 2 3  4。所以算法需要改进。

    改进后的代码(WA):

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<malloc.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define SIZE 1000001
    #define MOD 1000001
    
    typedef struct node
    {
       int id,cnt;
       struct node * next;    
    } Node;
    
    
    int a[SIZE],b[SIZE];
    int num;
    Node x[SIZE];
    Node *search(Node x[],int n,int k);
    void insert(Node x[],int n,int k);
    
    int main()
    {
      int T,i,n,first,end,ff,ee,r1,r2,rr2;
      //freopen("in.txt","r",stdin);
      //freopen("me.txt","w",stdout);
    /*
     18
     1 2 2 3 3 4 4 2 1 4 3 1 2 2 3 3 4 4 
     18
     1 2 2 3 3 4 4 1 2 3 4 1 2 2 3 3 4 4
    */
      scanf("%d",&T);
      getchar();
      
         do
         {
    	   num = 0;
           for(i = 0 ; i < SIZE ; ++i)
           {
             x[i].id = -1;
             x[i].next = NULL;    
           }
    	   
           scanf("%d",&n);
           for(i = 0 ; i < n ; ++i )
           {
             scanf("%d",&a[i]); 
             b[i]=a[i];    
             insert(x,SIZE,a[i]);   
           }   
    
           for(first = 0 ;(search(x,SIZE,a[first])->cnt) > 1   ; ++first)
            --(search(x,SIZE,a[first])->cnt) ; 
    	   
    	   for(end = n-1 ; (search(x,SIZE,a[end])->cnt) > 1 ; --end)
             --(search(x,SIZE,a[end])->cnt) ;
           
    
    	   r1 = end - first + 1;
    
    	  i = 0 ; rr2=1000000;
    
    	  while(i <= end)
    	  {
    	     if(a[i] == a[first])
    		 {
    		     ff = i; 
    			 
    	         ++i;
    			 for(;a[i] != a[end];++i);
    			 ee = i;
    			  if(i>end) break;
    
                 sort(b+ff,b+ee+1);
                 for(i = ff ; i <= ee ; ++i)
    				   b[i] = a[i];
    		     int k = 1;
    		    for(i = ff+1 ; i <= ee ; ++i )
    			{
    	           if(b[i] != b[i-1])
    			   ++k;
    			}
                r2 = ee -ff + 1 ;
                if(k == num && r2 < rr2)
    		     rr2 = r2;
    		     ++ee;
    		    while(a[ee] == a[end]) ++ee;
                 --ee;
                 i = ee;
                 
    		 }
    	     else
    		 {
    		   if(a[i] == a[end])
    		   {
    		       ee = i;  
    			   
    	           ++i;
    			   for(;a[i] != a[first];++i);
    			   ff = i;
    			   if(i>end) break;
    			    
                   sort(b+ee,b+ff+1);
    			   for(i = ee ; i <= ff ; ++i)
    				   b[i] = a[i];
    
    		       int k = 1;
    		      for(i = ee+1 ; i <= ff ; ++i )
    			  {
    	             if(b[i] != b[i-1])
    			     ++k;
    			  }
                   r2 = ff-ee + 1 ;
                  if(k == num && r2 < rr2)
    		       rr2 = r2;
    		       ++ff;
    		       while(a[ff] == a[first]) ++ff;
    			   --ff;
    			   i = ff;
    			   
    		   }//if
    		   else
    			   ++i;
    			    if(i>end) break;
    		 }//else
    		
    	  }//while()
    
    	   printf("%d\n",rr2<r1? rr2:r1);
         }while(--T);      
        
      system("pause");
      return 0;    
    }
    
    Node *search(Node x[],int n,int k)
    {
       Node* p;
       int pos;
       pos = k % MOD;
       p = &x[pos];      
       while(p && p->id != k)
       p = p->next;
       return p;  
    }
    
    void insert(Node x[],int n,int k)
    {
      Node *p,*one;
      int pos;
      one = (Node *)malloc(sizeof(Node));
      p = search(x,n,k); 
      if(p)
      {
          ++(p->cnt);     
          free(one);
      }    
      else
      {
    	++num;
        pos = k % MOD;
        one->next = x[pos].next;
        x[pos].next = one;  
        one->id = k;
        one->cnt = 1;  
      }   
    }
    

     我测了一下,只有2组数据错了。开头提到的那组数据是对的。

    但是这个算法依然是有bug的,因为我总是把子序列的开头和结尾定死了(就是first 和 end 位置的那两个数),显然是不对的。

    比如这组数据:

    18
     1 2 2 3 3 4 4 2 4 1 3 1 2 2 3 3 4 4

          我的代码运行结果是6,但是结果应该是4,我得出的子序列是后面的1 2 2 3 3 4 ,但是中间的 2 4 1 3 也满足条件,而且长度最短,为4.它的两端是2 和3,而我的算法规定开头和结尾只能是first 和 end位置上的数。

    必须谨记:

    1.子序列开头和结尾是不能固定的,所以可以穷举;

    2.如果穷举,有两种结果:

      (1)超时,蛮力穷举必然超时;

      (2)AC,这就要进行巧妙的穷举,就是有些显然不符合的,直接跳过。

    3.如果不穷举,应该还有高招,请路过的大牛指点。

    正在思考中……

  • 相关阅读:
    Java中String、StringBuffer和StringBuilder的区别
    Map集合学习
    Set集合学习
    List集合学习
    常用集合类简介及线程安全和非线程安全的集合对象
    JQuery入门
    原生Ajax使用
    JavaScript闭包
    Demo:servlet实现图片的上传
    Android Handler 内存泄漏问题
  • 原文地址:https://www.cnblogs.com/HpuAcmer/p/2276862.html
Copyright © 2020-2023  润新知