*菜鳥寶寶第一次寫博客麼麼噠~~
劉汝佳老師的《算法競賽入門經典》中例題和推薦題目的代碼,本寶寶寫了一份java版的,放在http://github.com/MelissaChan/SFJSRMJD.git,持續更新中~*
咳咳~下面進入正題~
- 介紹數組前綴和&計數排序
- 例1:UVA10474(Where is the Marble?)
- 例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:)