數組前綴和 & 計數排序 uva10474 hdu5327

*菜鳥寶寶第一次寫博客麼麼噠~~
劉汝佳老師的《算法競賽入門經典》中例題和推薦題目的代碼,本寶寶寫了一份java版的,放在http://github.com/MelissaChan/SFJSRMJD.git,持續更新中~*


咳咳~下面進入正題~

  1. 介紹數組前綴和&計數排序
  2. 例1:UVA10474(Where is the Marble?)
  3. 例2:HDU5327(Olympiad)

Q:數組前綴和是用來幹嘛的?
A:數組排序、查詢一個區間內有多少個符合條件的數。

Q:爲什麼用它?
A:快。

Q:數組前綴和和計數排序有什麼關係?
A:一樣的方法。


大家喜聞樂見的代碼在這裏:

//數組前綴和

//int[] data是需要排序的數組,k是data中的最大值

    //先開一個輔助數組,長度爲K
    int[] tmp = new int[k + 1];

    //第一個for,統計data中相同數據出現的次數,以數據爲下標,出現次數爲值,存儲到temp  
    for (int i = 0; i < data.length; i++) {  
        tmp[data[i]]++;  
    }  
    //第二個for,統計temp中每個元素前有幾個數
    for (int j = 1; j <= k; j++) {  
        tmp[j] = tmp[j] + tmp[j-1];  
    } 
//現在我們就得到了一個temp數組,每個下標對應的值都是原序列中,小於等於該值的數據出現的次數。
//temp[5] = 3 表示在data中<=5的數據有三個,也表示6(如果有)在data中是第三大的數字
//計數排序

//時間複雜度O(n)
//限制:所有值都不大於k,而且是非負整數 

package Sort_Search;

public class CountSort {  
    //data是待排序數組,k爲data中的最大值
    public static int[] countSort(int[] data, int k) { 
        //以下同數組前綴和 
        int[] tmp = new int[k + 1];  
        for (int i = 0; i < data.length; i++) {  
            tmp[data[i]]++;  
        }  
        for (int j = 1; j <= k; j++) {  
            tmp[j] = tmp[j] + tmp[j-1];  
        }
        //將排序結果轉換到result裏返回
        int[] result = new int[data.length];  
        for (int i = data.length - 1; i >= 0; i--) {  
            result[tmp[data[i]] - 1] = data[i];  
            tmp[data[i]]--;  
        }  
        return result;  
    }  
}  

UVA10474(Where is the Marble?)

~原題鏈接點這裏啦~

題目大意:
給定一個數組,排序,輸出查詢的數字在序列裏的位置。

寶寶的代碼:

package UVaOJ;

import java.util.Arrays;
import java.util.Scanner;

public class P10474 {

    public static void main(String[] args) {
        //input
        Scanner sc = new Scanner(System.in);
        int count = 0;
        while(sc.hasNext()){
            int total = sc.nextInt();
            int quary = sc.nextInt();
            if(total ==  0 && quary == 0) break;
            System.out.println("CASE# " + (++count) +":");
            int[] nums = new int[total];
            int temp2 = total;
            while(temp2-- > 0){
                nums[temp2] = sc.nextInt();
            }

        //方法一:sort加二分
            Arrays.sort(nums);
            while(quary-- > 0){
                int q  = sc.nextInt();
                int ans = binarySearch(nums,q);
                while(ans > 0 && nums[ans-1] == nums[ans])
                    ans--;
                if(ans >= 0)
                    System.out.println(q+" found at "+(ans+1));
                else System.out.println(q+" not found");
            }


        //方法二:赤裸裸的數組前綴和
            int[] temp = new int[10100];
            for(int i = 0; i < total;i++){
                temp[nums[i]]++;
            }
            for(int i =1;i < 10100; i++){
                temp[i] = temp[i] + temp[i-1];
            }
            while(quary-- > 0){
                int q  = sc.nextInt();
                System.out.print(q);
                int ans2 = temp[q-1];
                if(temp[q] == temp[q-1])    
                System.out.println(" not found");
                else System.out.println(" found at "+(ans2 + 1));
            }

        }
        sc.close();
    }

    //額,這是一個手寫的二分查找
    public static int binarySearch(int[] data, int key){
        if(data.length > 0){
            int low = 0;
            int high = data.length - 1;
            while(low <= high){
                int mid = (low + high) / 2;
                if(key == data[mid])
                    return mid;
                else if(key > data[mid]){
                    low = mid + 1;
                }
                else {
                    high = mid - 1;
                }
            }
        }
        return -1;
    }
}

HDU5327(Olympiad)

~原題鏈接點這裏啦~
題目大意:
輸出區間[a,b]上“美麗數”的個數。(美麗數就是每位都不同的數,比如說123,而112就不是美麗數)

寶寶的代碼:

package HDU;

import java.util.Scanner;

public class P5327 {
    //判斷是不是美麗數
    public static int isButifulNumber(int num){
        int[] temp = new int[10];
        int count = 0;
        while(num > 0){
            temp[count] = num % 10; 
            num /= 10;
            count++;
        }
        for(int i = 0; i < count; i++)
            for(int j = 0; j < count; j++)
                if(i != j && temp[i] == temp[j]) 
                    return 0;
        return 1;
    }

    public static void main(String[] args) {
    //把每個數之前有多少個美麗數存到nums數組裏,那麼區間[a,b]上的美麗數個數就是nums[b]-nums[a-1]了
        Scanner sc = new Scanner(System.in);
        //還是赤裸裸的數組前綴和
        int[] nums = new int[100100];
        //第一個for之後,nums中只有0和1,代表該數是否是美麗數
        for(int i = 1; i < 100100;i++){
            nums[i] = isButifulNumber(i);
        }
        //統計
        for(int j = 1; j <100100;j++){
            nums[j] = nums[j] + nums[j-1];
        }
        //輸入輸出
        int n = sc.nextInt();
        while(n-- > 0){
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(nums[b] - nums[a-1]);
        }
        sc.close();
    }

}

~end~


話外:菜鳥寶寶最近開始學着刷一些水題,老是喜歡用一些現成的容器,比如說集合類來簡化代碼,可是一交一個WA,還查不出錯誤。事後悔過應該是因爲自己對這些容器的特性和具體實現不夠了解。今後要多用數組什麼的,不着急,一步一步的來。不比誰寫的程序炫酷,比的是誰能更好更快的解決問題,get:)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章