平均时间复杂度 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]; } }