牛客網演算法初級班(一)
阿新 • • 發佈:2018-12-18
一、認識時間複雜度
常數時間的操作:一個操作如果和資料量沒有關係,每次都 固定時間內完成的操作,叫做常數操作。
時間複雜度為一個演算法流程中,常數運算元量的指標。常用O(讀作big O)來表示。具體來說,在常數運算元量的表示式中, 只要高階項,不要低階項,也不要高階項的係數,剩下的部分如果記為f(N),那麼時間複雜度為O(f(N))。
評價一個演算法流程的好壞,先看時間複雜度的指標,然後再分析不同資料樣本下的實際執行時間,也就是常數項時間。
二、一個簡單的理解時間複雜度的例子
例子:一個有序陣列A,另一個無序陣列B,請列印B中的所有不在A中的數,A數 組長度為N,B陣列長度為M。演算法流程1
:對於陣列B中的每一個數,都在A中通過遍歷的方式找一下;// a有序, b無序 public static void square(int[] a, int[] b){ boolean flag = false; for (int i = 0; i < b.length; i++) { for (int j = 0; j < a.length; j++) { // 如果b中的元素在a中存在,跳出迴圈,不列印該元素 if (b[i] == a[j]){ flag = true; break; } } if (!flag) System.out.print(b[i] + " "); flag = false; } System.out.println(); }
分析:時間複雜度O(),空間複雜度O(1)演算法流程2:對於陣列B中的每一個數,都在A中通過二分的方式找一下;
public static void binary(int[] a, int[] b){ boolean flag = false; for (int i = 0; i < b.length; i++) { int left = 0, right = a.length - 1; flag = false; while (left <= right){ int mid = left + (right - left) / 2; if (a[mid] == b[i]){ flag = true; break; } if (a[mid] < b[i]) left = mid + 1; else if (a[mid] > b[i]) right = mid - 1; } if (!flag) System.out.print(b[i] + " "); } System.out.println(); }
分析:時間複雜度O(N*logN),空間複雜度O(1)演算法流程3:先把陣列B排序,然後用類似外排的方式列印所有在A中出現的數;
// a有序, b無序 public static void sort(int[] a, int[] b){ Arrays.sort(b); int i = 0, j = 0; while (i < b.length && j < a.length){ if (b[i] < a[j]) System.out.print(b[i++] + " "); else if(b[i] > a[j]) j++; else i++; } if (i < b.length && j == a.length && b[i] == a[j-1]) i++; while (i < b.length){ System.out.print(b[i] + " "); i++; } System.out.println(); }
三、對數器的概念和使用
0,有一個你想要測的方法a(比如,氣泡排序演算法)
public static void bubbleSort(int[] arr){ if (arr == null || arr.length < 2) return; for (int end = arr.length - 1; end > 0; end --){ for (int i = 0; i < end; i++){ if (arr[i] > arr[i+1]) swap(arr, i, i+1); } } }
1,實現一個絕對正確但是複雜度不好的方法b,
// 在排序演算法中,直接呼叫Arrays.sort(arr); public static void comparator(int[] arr) { Arrays.sort(arr); }
2,實現一個隨機樣本產生器
public static int[] generateRandomArray(int maxSize, int maxValue) { // 陣列長度: [0, size] // Math.random() [0, 1) int[] arr = new int[(int) ((maxSize + 1) * Math.random())]; for (int i = 0; i < arr.length; i++) { arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random()); } return arr; }
3,實現比對的方法
public static int[] copyArray(int[] arr) { if (arr == null) { return null; } int[] res = new int[arr.length]; for (int i = 0; i < arr.length; i++) { res[i] = arr[i]; } return res; } public static boolean isEqual(int[] arr1, int[] arr2) { if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) { return false; } if (arr1 == null && arr2 == null) { return true; } if (arr1.length != arr2.length) { return false; } for (int i = 0; i < arr1.length; i++) { if (arr1[i] != arr2[i]) { return false; } } return true; }
4,把方法a和方法b比對很多次來驗證方法a是否正確,並列印樣本分析是哪個方法出錯。
public static void main(String[] args) { int testTime = 500000; int maxSize = 100; int maxValue = 100; boolean succeed = true; for (int i = 0; i < testTime; i++) { int[] arr1 = generateRandomArray(maxSize, maxValue); int[] arr2 = copyArray(arr1); bubbleSort(arr1); comparator(arr2); if (!isEqual(arr1, arr2)) { succeed = false; System.out.println("#########################################################"); System.out.println("my array : "); printArray(arr1); printArray(arr2); System.out.println("right array : "); System.out.println("#########################################################"); break; } } System.out.println(succeed ? "Nice!" : "Fucking fucked!"); int[] arr = generateRandomArray(maxSize, maxValue); printArray(arr); selectSort(arr); printArray(arr); }