1. 程式人生 > >枚舉算法的思想專題

枚舉算法的思想專題

ger 長度 情況 包含 如果 closed 裏的 sys 面試題

枚舉算法的思想例題

solution0:

技術分享圖片

solution1:

思路1:由於要求最大值直接逆向枚舉即可:最大的是9876543210,最小的是題目中給的1026753849。然後我們去判斷是不是恰好包含0~9十個數字。再判斷是不是完全平方數

技術分享圖片
 1 static void solution1(){
 2     Long i;
 3     for (i = 9876543210L; i > 1026753849; i--) {
 4         double q = (int)Math.sqrt(i*1.0);
 5         if(q*q==i){
6 if(test(i)){ 7 System.out.println(i); 8 break; 9 } 10 } 11 } 12 }
View Code

思路2:枚舉平方根,十位數的平方根,最小是30000,最大我們這裏設的是100000,綽綽有余。然後我們根據Y算出X,這樣X一定是完全平方數,我們也不用檢查了。只用檢查X是不是恰好十個數字:

技術分享圖片
 1 static void solution2(){
 2     for (int
i=100000;i>30000;i--){ 3 long x= (long)i*i; 4 // System.out.println(x); 5 if(test(x)){ 6 System.out.println(x); 7 break; 8 } 9 } 10 }
View Code

判斷是否重復的公共代碼:

技術分享圖片
 1 private static boolean test(Long i) {
 2     Set<Integer> myset=new
HashSet<>(); 3 long x=i; 4 while (x!=0){ 5 int l = (int) (x % 10); 6 myset.add(l); 7 x/=10; 8 } 9 return myset.size()==10; 10 }
View Code

總結:這個算法的復雜度就比之前的算法低了很多。枚舉大概是10^5量級,判斷是不是恰好十個數字還有O(10)的復雜度,總共大概是10^6量級。

solution2:

技術分享圖片

思路1: 一拿到題目不難看出,直接枚舉數組的每一位,加上相應的差值,然後再次遍歷數組看是否存在相應的值在這個數組中,然後處理重復即可得到答案,但是這個復雜度為O(N2),這裏出現一個O(N)巧妙解法

 1  // O(N) example1
 2     static void solution2(){
 3         int n,k,ans=0;
 4         n=in.nextInt();
 5         k=in.nextInt();
 6         Set<Integer> myset =new HashSet<>();
 7         for(int i=0;i<n;i++){
 8             myset.add(in.nextInt());
 9         }
10         for(Integer x:myset){
11             if (myset.contains(x+k)){
12                 ans++;
13             }
14         }
15         System.out.println(ans);
16     }

solution3:

下面我們再看一道題,叫一面磚墻。這道題改編自網上Facebook去年的一道面試題,是hihoCoder的1494題(https://hihocoder.com/problemset/problem/1494

技術分享圖片

思路: 我拿到這個題目,直覺就是無法模擬出來,各個磚塊之間好像又沒有什麽聯系,但是仔細想一想 看下面的圖,紅色的線條即為 最優的穿墻答案,所以我們可以想到,在兩塊磚的縫隙處就是我們要找的答案,又可以發現

在磚塊長度不一致的情況下 有寬度重合的地方,這個地方我們剛好可以用X坐標表示,那麽在讀入的時候,X坐標的重復的次數即為要,最終要穿透的位置。

技術分享圖片

 1 static void solution3(){
 2         int N;
 3         Map<Integer,Integer> mycoor=new HashMap<>();
 4         N=in.nextInt();
 5         for(int i=0;i<N;i++){
 6             int n,cnt=0;
 7             n=in.nextInt();
 8             for(int j=0;j<n;j++){
 9                 int xk=in.nextInt();
10                 cnt+=xk;
11                 Integer x1 = mycoor.get(cnt);
12                 if (x1==null) x1=0;
13                 if (j!=n-1)mycoor.put(cnt,++x1);
14                 System.out.println(x1);
15             }
16         }
17         int max=0;
18         for (Map.Entry<Integer,Integer> x:mycoor.entrySet()){
19               max=Math.max(x.getValue(),max);
20         }
21         System.out.println(N-max);
22     }

solution4:

技術分享圖片

上面這道題目看似就是一道範圍枚舉題目,但是實際上需要完全的AC 需要註意的地方非常多,如果縮短時間復雜度 構造解析的等式的;

一般做法就是枚舉 這個等式 a^2+b^2+c^2+d^2=N 範圍如下圖,但是時間復雜度太高:【這裏的/4 /3 /2 /1=再開放是為了 構造滿足提議要求的遞增規律】

技術分享圖片

所以可以分部分構造解: 把後一分部解提前構造出來:

技術分享圖片

 1 static void solution1(){
 2         Map<Integer,Integer> f=new HashMap<>();
 3         int N=in.nextInt();
 4         //構造後部分解
 5         for(int c=0;c*c<=N/2;c++){
 6             for (int d=c;d*d+c*c<=N;d++){
 7                 if (!f.containsKey(d*d+c*c)){
 8                     f.put(c*c+d*d,c);
 9                 }
10             }
11         }
12         //構造前部分解
13         for (int a=0;a*a*4<=N;a++){
14             for (int b=a;b*b+a*a<=N/2;b++){
15                 if(f.containsKey(N-a*a-b*b)){
16                     Integer c = f.get(N - a * a - b * b);
17                     int d= (int) Math.sqrt((N-a*a-b*b-c*c)+1e-3);
18                     System.out.println(a+" "+b+" "+c+" "+d);
19                     return;
20                 }
21             }
22         }
23     }

枚舉算法的思想專題