平均時間複雜度 O(n^2) ,空間複雜度 O(1),穩定java
基本思想算法
演示(圖片來自菜鳥教程)數組
代碼函數
/** * 冒泡排序 * @param array 待排序的數組 */ public static void bubbleSort(int[] array) { for(int i=0; i<array.length-1; i++){ for(int j=array.length-1; j>i; j--){ if(array[j] < array[j-1]){ int temp = array[j]; array[j] = array[j-1]; array[j-1] = temp; } } } }
平均時間複雜度 O(n^2) ,空間複雜度 O(1),不穩定優化
基本思想ui
i
小的元素,而後把它和第i
個元素交換位置演示設計
代碼3d
/** * 選擇排序 * @param array 待排序的數組 */ public static void selectSort(int[] array) { for(int i=0;i<array.length-1;i++){ int minIndex = i; for(int j=i+1;j<array.length;j++){ if(array[j]<array[minIndex]){ minIndex = j; } } if(minIndex != i){ int temp = array[i]; array[i] = array[minIndex]; array[minIndex] = temp; } } }
平均時間複雜度 O(n^2) ,空間複雜度 O(1),穩定code
基本思想blog
i
個數已經排好序了,那麼第 i+1
個數只須要插入到前面已經排好序的數組中便可演示(圖片來自菜鳥教程)
代碼
/** * 插入排序 * @param array 待排序的數組 */ public void insertSort(int[] array) { for (int i = 0; i < array.length - 1; i++) { for (int j = i + 1; j > 0; j--) { if (array[j] < array[j-1]) { int temp = array[j-1]; array[j-1] = array[j]; array[j] = temp; } else { break; } } } }
平均時間複雜度 O(n log(n)) ,空間複雜度 O(n),穩定
基本思想(分治)
演示(圖片來自菜鳥教程)
代碼
/** * 歸併排序 * @param array 須要排序的數組 * @return 排好序的數組 */ public int[] mergeSort(int[] array) { // 建立額外的空間 int[] res = Arrays.copyOf(array, array.length); if (res.length < 2) { return res; } int mid = array.length / 2; int[] left = Arrays.copyOfRange(array, 0, mid); int[] right = Arrays.copyOfRange(array, mid, array.length); return merge(mergeSort(left), mergeSort(right)); } /** * 歸併兩個有序數組 * @param array1 有序數組1 * @param array2 有序數組2 * @return 歸併後的新數組 */ private int[] merge(int[] array1, int[] array2) { int[] res = new int[array1.length + array2.length]; int p = 0; int i = 0; int j = 0; while (i < array1.length && j < array2.length) { if (array1[i] <= array2[j]) { res[p++] = array1[i++]; } else { res[p++] = array2[j++]; } } // 剩下了left while (i < array1.length) { res[p++] = array1[i++]; } // 剩下的是right while (j < array2.length) { res[p++] = array2[j++]; } return res; }
平均時間複雜度 O(n log(n)) ,空間複雜度 O(log n),不穩定
算法思想(分治)
演示(圖片來自菜鳥教程)
具體操做
i=0,j=n-1,key=array[i]
j
向前移動,找到第一個比 key
小的元素,把這個元素放到 i
i
向後移動,找到第一個比 key
大的元素,將它放到 j
的位置i
的地方放上 key
[0,i-1]
中全部的元素都是比 i
小的,[j,n-1]
中的全部元素都是比 i
大 的,而後重複操做,直到 i==j
這樣就知足了 array[0,i-1] < array[i] < array[i+1,n-1]
。而後 i
左右兩邊的區間重複操做。代碼
/** * @param array 須要排序區間所在的數組 * @param left 區間的起始下標 * @param right 區間的結束下標 */ public void quickSort(int[] array, int left, int right) { if (left < right) { int i = left; int j = right; int key = array[left]; while (i < j) { // 從j開始向左尋找到第一個比 key 小的數 while (i < j && array[j] >= key) { j--; } if (i < j ) { array[i] = array[j]; i++; } // 從i開始向右尋找第一個大於等於 key 的數 while (i < j && array[i] < key) { i++; } if (i < j) { array[j] = array[i]; j--; } } array[i] = key; quickSort(array, left, i-1); quickSort(array, i+1, right); } }
平均時間複雜度 O(n+k) ,空間複雜度 O(k),穩定
什麼是堆?
基本思想
i
的元素,他的左右孩子的下標是 2i+1
和 2i+2
演示
代碼
/** * 堆排序 * @param array 待排序的數組 */ public void heapSort(int[] array) { // len表示的是未進行排序的長度 int len = array.length; for (int i = 0; i < array.length; i++) { // 從最後一個非葉子節點開始調整,使其知足大頂堆的性質 int last = len / 2 - 1; for (int j = last; j >= 0; j--) { int left = 2 * j + 1; int right = left + 1; if (array[left] > array[j]) { swap(array, left, j); } if (right < len && array[right] > array[j]) { swap(array, right, j); } } len--; // 將堆頂元素和放到正確的地方 swap(array, 0, array.length - 1 - i); } } /** * 交換數組中的兩個元素 * @param array 數組 * @param i1 元素1 * @param i2 元素2 */ private void swap(int[] array, int i1, int i2) { int temp = array[i1]; array[i1] = array[i2]; array[i2] = temp; }
平均時間複雜度 O(n+k) ,空間複雜度 O(k),穩定。其中,k是整數的範圍
基本思想
演示
代碼
/** * 計數排序 * @param array 待排序的數組 */ public void countingSort(int[] array) { int min = array[0]; int max = array[0]; // 找最大值和最小值 for (int i : array) { min = Math.min(i, min); max = Math.max(i, max); } // 申請額外的空間,大小爲最值之間的範圍 int[] temp = new int[max - min + 1]; // 填充新數組 for (int i : array) { temp[i - min]++; } // 遍歷新數組,而後填充原數組 int index = 0; for (int i = 0; i < temp.length; i++) { if (temp[i] != 0) { Arrays.fill(array, index, index + temp[i], i + min); index += temp[i]; } } }
注意:計數排序對於必定範圍內的整數進行排序具備最高的效率,前提是整數的範圍不要太大
平均時間複雜度 O(n) ,空間複雜度 O(n+k),穩定。其中k是桶的數量
基本思想
關鍵
演示
代碼
思路
key
來講,在進行一次快速排序的過程當中,是能夠肯定出這個 key
所在有序數組中的位置。K
便可。若是比 k
大,則在 key
的右邊再作一次快速排序便可;反之,則在左邊作一次快速排序時間複雜度 O(n),空間複雜度 O(1)
代碼
public int findKthLargest(int[] nums, int k) { int left = 0; int right = nums.length - 1; int target = nums.length - k; while (left < right) { int p = quickSort(nums, left, right); if (p < target) { left = p + 1; } else if (p > target) { right = p - 1; } else { return nums[p]; } } return nums[left]; } // 快速排序函數,返回key的下標 public int quickSort(int[] array, int left, int right) { int i = left; int j = right; int key = array[left]; while (i < j) { while (i < j && array[j] >= key) { j--; } if (i < j) { array[i] = array[j]; i++; } while (i < j && array[i] < key) { i++; } if (i < j) { array[j] = array[i]; j--; } } array[i] = key; return i; }
注意點
k=1
時,函數可能不會在循環體中返回結果。此時,退出循環後left=5
,因此要返回 nums[left]
思路
代碼
public int[] topKFrequent(int[] nums, int k) { int[] res = new int[k]; // 用哈希表作桶排序,每一個元素做爲key,出現次數做爲value Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0)+1); } int[][] bucket = new int[map.size()][2]; int p = 0; // 利用數組將元素和出現次數進行對應 for (Integer i : map.keySet()) { bucket[p][0] = i; bucket[p++][1] = map.get(i); } // 降序排序 Arrays.sort(bucket, ((o1, o2) -> o2[1]-o1[1])); for (int i = 0; i < k; i++) { res[i] = bucket[i][0]; } return res; }
優化
代碼
// 再對頻率進行一次桶排序,這樣就能夠獲得前K個高頻的元素 // 對於頻率最高的元素,放在最前面 List<Integer>[] bucket = new List[maxFrequency + 1]; for (int i : map.keySet()) { int f = maxFrequency - map.get(i); if (bucket[f] == null) { bucket[f] = new ArrayList<>(); } bucket[f].add(i); } List<Integer> res = new ArrayList<>(); int i = 0; while (k > 0) { List<Integer> list = bucket[i++]; if (list != null) { res.addAll(list); k -= list.size(); } }
思路
代碼
public String frequencySort(String s) { Map<Character, Integer> map = new HashMap<>(); // 對字母進行桶排序,獲得每一個字母出現的頻率 int max = 0; for (int i = 0; i < s.length(); i++) { map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1); max = Math.max(max, map.get(s.charAt(i))); } // 再對頻率進行一次桶排序 ArrayList<Character>[] bucket = new ArrayList[max + 1]; for (char c : map.keySet()) { int f = map.get(c); if (bucket[f] == null) { bucket[f] = new ArrayList<>(); } bucket[f].add(c); } int p = 0; char[] chars = s.toCharArray(); for (int i = max; i >= 0; i--) { if (bucket[i] != null) { for (char c : bucket[i]) { Arrays.fill(chars, p, p+i, c); p += i; } } } return new String(chars); }
思路
代碼
public void sortColors(int[] nums) { int[] f = new int[3]; for (int num : nums) { f[num]++; } int p = 0; for (int i = 0; i < 3; i++) { Arrays.fill(nums, p, p + f[i], i); p += f[i]; } }