力扣题目
解题思路
java代码
力扣题目:
给你一个整数数组 nums
,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1] 输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0] 输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104
解题思路:
手撕快速排序
冒泡排序
冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
快速排序
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个元素要O(n log n)次比较。在最坏状况下则需要O(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(n log n)算法更快,因为它的内部循环(inner loop)可以在大多数的架构上很有效率地被实现出来。
代码中的快速排序还加入了一种优化手段:随机化快速排序。通过在分割前将数组中的元素随机打乱,可以减少出现最坏情况的可能性,从而提高排序效率。
解题思路
-
冒泡排序:通过双重循环,不断地比较相邻的两个元素,如果前者比后者大,则交换它们的位置。每一轮循环后,最大的元素会被放到数组的末尾。然后对剩下的数组重复这个过程。
-
快速排序:
- 选择主元:随机选择一个元素作为主元(pivot)。
- 分区操作:将数组分为两部分,左边都是小于等于主元的元素,右边都是大于主元的元素。主元最后会位于数组的中间位置。
- 递归排序:对主元左边的数组和右边的数组递归地进行快速排序。
这两种算法的时间复杂度不同,冒泡排序的平均和最坏时间复杂度都是O(n^2),而快速排序的平均时间复杂度是O(n log n),最坏情况是O(n^2)。在实际应用中,快速排序通常比冒泡排序更受欢迎,因为它在大多数情况下的性能更好。
java代码:
package org.example;
import java.util.Random;
public class Leetcode912 {
public static void main(String[] args) {
int[] nums = {5, 1, 1, 2, 0, 0};
}
// 冒泡排序
public int[] sortArray(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
return nums;
}
/**
* @DisplayName 快速排序
* @DataSource排序
* @param nums
* @return // 随机化快速排序, 降低最坏情况下的时间复杂度, 降低空间复杂度, 降低不稳定性
*/
public int[] sortArray3(int[] nums) {
quicksort(nums, 0, nums.length - 1);
return nums;
}
// 快速排序
// 快速排序, 递归
public void quicksort(int[] nums, int l, int r) {
if (l < r) {
// 随机化分区, 先找到主元对应的位置
int pos = randomRegion(nums, l, r);
// 递归, 分治, 将剩下的数组分成两个子数组, 递归地排序
quicksort(nums, l, pos - 1);
quicksort(nums, pos + 1, r);
}
}
public int randomRegion(int[] nums, int l, int r) {
int i = new Random().nextInt(r - l + 1) + l; // 随机选一个作为我们的主元
// 将主元交换到数组的最后一个位置
exchange(nums, r, i);
return separate(nums, l, r);
}
/**
* 作用: 快速排序的分区操作
*/
public int separate(int[] nums, int l, int r) {
int pivot = nums[r]; // 主元的值
int i = l - 1; // 哨兵
// 遍历数组,将小于主元的值交换到左边,将大于主元的值交换到右边
for (int j = l; j <= r - 1; ++j) {
if (nums[j] <= pivot) {
i = i + 1;
// 交换
exchange(nums, i, j);
}
}
// 交换主元和哨兵
exchange(nums, i + 1, r);
return i + 1;
}
private void exchange(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
更多详细内容同步到公众号,感谢大家的支持!
并且没有任何收费项