题目地址
选择排序
运行逻辑
- 遍历数组0到倒数第二个数字, 遍历到第i个数的时候, 将第i个数 和 i+1个数往后的所有数字作比较, 找到一个最小的数字, 将其值和第i个数交换.
- 整体思路: 找到第一小和第一个数互换, 第二小和第二个数互换....
代码
注意点
- 需要一个局部变量minIndex标识当前最小元素
- i 从 0 ~ len-1, 因为倒数第一个数, 没有数字和他比较了, 不需要排了
- j从 i+1 ~ len 因为第i个数已经被拿走.
class Solution {
public int[] sortArray(int[] nums) {
int len = nums.length;
// 取出数组所有元素
for (int i = 0; i < len - 1; i ++) {
// 局部变量i为起始, minIndex保存最小元素
int minIndex = i;
for (int j = i + 1; j < len; j++) {
if (nums[j] < nums[minIndex]) {
minIndex = j;
}
}
swap(minIndex, i, nums);
}
return nums;
}
public void swap(int minIndex, int i, int[] nums) {
int tmp = nums[minIndex];
nums[minIndex] = nums[i];
nums[i] = tmp;
}
}
复杂度
- 一共n个数字, 第一个数字要和n-1个数字比较, 第二个数字要和n-2个数字比较...
- 求和 1+2+3+...+n = big O(n^2)
插入排序
运行逻辑
- 第i个数, 如果前面的3个数比他大, 就先将3个比他大的数后移, 然后将第i个数插入这三个数字的前面
代码
class Solution {
public int[] sortArray(int[] nums) {
int len = nums.length;
// 插入排序 1~len个元素往前插入
// 1 3 4 2 比如 2 比 3 4 小, 3 4 后移动, 2放在3现在的位置上
for (int i = 1; i < len; i++) {
int temp = nums[i]; //保存当前数字
int j = i;
// 比当前数大的数, 后移
while (j > 0 && nums[j-1] > temp) {
nums[j] = nums[j-1];
j--;
}
nums[j] = temp;
}
return nums;
}
}
特点
- 插入排序」可以提前终止内层循环(体现在 nums[j - 1] > temp 不满足时),在数组「几乎有序」的前提下,「插入排序」的时间复杂度可以达到 O(N), 因此插入排序在短数组和几乎有序数组表现良好
复杂度
- 时间复杂度:O(N^2)
归并排序 MergeSort
运行逻辑
- 合并两个有序数组, 如{1}, {2} 合并成{1,2}, 又如{1, 2},{3,4} 合并成{1,2,3,4}, 利用递归的思想进行合并
API
- System.arraycopy
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
代码
class Solution {
public int[] sortArray(int[] nums) {
mergeSort(nums, 0, nums.length - 1, new int[nums.length]);
return nums;
}
public void mergeSort(int[] nums, int start, int end, int[] temp) {
if (start >= end) return;
int mid = start + (end - start) / 2;
mergeSort(nums, start, mid, temp);
mergeSort(nums, mid+1, end, temp);
// 合并两个排序好的数组,
int i = start;
int j = mid+1;
int cur = 0;
// 合并数组保存到temp中, 此时左边右边都有数
while (i<=mid&&j<=end) {
if (nums[i]<=nums[j]) temp[cur] = nums[i++];
else temp[cur] = nums[j++];
cur++;
}
// 右半部分没有数字了
while (i<=mid) {
temp[cur++] = nums[i++];
}
// 左半部分没有数字了
while (j<=end) {
temp[cur++] = nums[j++];
}
// 保存到nums中
System.arraycopy(temp, 0, nums, start, end - start + 1);
}
}
要点
- 新建一个temp数组和nums同样大小, 来保存每次合并好的数组(因为不能在nums上直接改动, 每次需要新建很麻烦)
- 每次都会将一个数组, 拆封成两部分, 进行排序
- 将排序的数组合并
- 分冶法 下面这图很形象
复杂度
- nlogn