目录
[21. 调整数组顺序使奇数位于偶数前面](#21. 调整数组顺序使奇数位于偶数前面)
[45. 把数组排成最小的数](#45. 把数组排成最小的数)
[51. 数组中的逆序对](#51. 数组中的逆序对)
BubbleSort
java
package Theoretical_foundation.Sort;
// ====================== 核心思路 ======================
// 题目:冒泡排序
// 思想:每一轮把当前最大的数"冒泡"到末尾
// 优化:如果某一轮没有交换,说明已经有序,提前结束
//
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
// 稳定排序
// ======================================================
import java.util.Arrays;
public class BubbleSort {
public int[] sort(int[] nums) {
int length = nums.length;
for (int i = 0; i < length - 1; i++) {
boolean notSwapFlag = true;
for (int j = 0; j < length - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums, j, j + 1);
notSwapFlag = false;
}
}
if (notSwapFlag) break;
}
return nums;
}
private void swap(int[] nums, int j, int i) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public static void main(String[] args) {
BubbleSort test = new BubbleSort();
int[] nums = new int[]{2, 5, 9, 3, 7, 4};
System.out.println(Arrays.toString(test.sort(nums)));
}
}
InsertionSort
java
package Theoretical_foundation.Sort;
// ====================== 核心思路 ======================
// 类似打扑克牌插牌,左边始终有序,每次把当前元素插入正确位置
//
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
// 稳定排序
// ======================================================
import java.util.Arrays;
public class InsertionSort {
public void sort(int[] nums) {
for (int i = 1; i < nums.length; i++) {
int cur = nums[i];
int j = i - 1;
while (j >= 0 && nums[j] > cur) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = cur;
}
}
public static void main(String[] args) {
InsertionSort test = new InsertionSort();
int[] nums = new int[]{2, 5, 9, 3, 7, 4};
test.sort(nums);
System.out.println(Arrays.toString(nums));
}
}
SelectionSort
java
package Theoretical_foundation.Sort;
// ====================== 核心思路 ======================
// 每轮选择最小值,放到当前位置
//
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
// 不稳定
// ======================================================
import java.util.Arrays;
public class SelectionSort {
public int[] sort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < nums[minIndex]) minIndex = j;
}
if (minIndex != i) swap(nums, minIndex, i);
}
return nums;
}
private void swap(int[] nums, int j, int i) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public static void main(String[] args) {
SelectionSort test = new SelectionSort();
int[] nums = new int[]{2, 5, 9, 3, 7, 4};
System.out.println(Arrays.toString(test.sort(nums)));
}
}
QuickSort
java
package Theoretical_foundation.Sort;
// ====================== 核心思路 ======================
// 快速排序:分治思想
// 选择一个基准值 pivot
// 左边都小于 pivot,右边都大于 pivot
// 递归左右区间
//
// 时间复杂度:平均 O(nlogn) 最坏 O(n^2)
// 空间复杂度:O(logn)
// ======================================================
import java.util.Arrays;
import java.util.Scanner;
public class QuickSort {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
QuickSort test = new QuickSort();
test.quickSort(nums, 0, n - 1);
System.out.println(Arrays.toString(nums));
}
private void quickSort(int[] nums, int start, int end) {
if (start >= end) return;
int pivot = partition(nums, start, end);
quickSort(nums, start, pivot - 1);
quickSort(nums, pivot + 1, end);
}
private int partition(int[] nums, int start, int end) {
int pivot = nums[start];
int first = start;
while (start < end) {
while (start < end && nums[end] >= pivot) end--; // 控制右指针向左移动,找到小于基准元素的那个数
while (start < end && nums[start] <= pivot) start++; // 控制左指针向右移动,找到大于基准元素的那个数
if (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
}
}
nums[first] = nums[start];
nums[start] = pivot;
return start;
}
}
MergeSort
java
package Theoretical_foundation.Sort;
import java.util.Arrays;
import java.util.Scanner;
// ====================== 核心思路 ======================
// 归并排序:分治 + 合并
// 不断二分,分别排序左右区间,合并两个有序数组
//
// 时间复杂度:O(nlogn)
// 空间复杂度:O(n)
// 稳定排序
// ======================================================
public class MergeSort {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
MergeSort test = new MergeSort();
test.mergeSort(nums, 0, n - 1);
System.out.println(Arrays.toString(nums));
}
private void mergeSort(int[] nums, int start, int end) {
if (start >= end) return;
int mid = (start + end) / 2;
mergeSort(nums, start, mid);
mergeSort(nums, mid + 1, end);
merge(nums, start, mid, end);
}
private void merge(int[] nums, int start, int mid, int end) {
int[] res = new int[end - start + 1];
int s1 = start, s2 = mid + 1;
int k = 0;
while (s1 <= mid && s2 <= end) {
if (nums[s1] <= nums[s2]) {
res[k++] = nums[s1++];
} else {
res[k++] = nums[s2++];
}
}
while (s1 <= mid) res[k++] = nums[s1++];
while (s2 <= end) res[k++] = nums[s2++];
for (int i = 0; i < res.length; i++) {
nums[start + i] = res[i];
}
}
}
HeapSort
java
package Theoretical_foundation.Sort;
// ====================== 核心思路 ======================
// 堆排序:大根堆
// 建堆,堆顶最大值交换到末尾,调整剩余堆
//
// 时间复杂度:O(nlogn)
// 空间复杂度:O(1)
// ======================================================
import java.util.Arrays;
import java.util.Scanner;
public class HeapSort {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
HeapSort test = new HeapSort();
test.heapSort(nums);
System.out.println(Arrays.toString(nums));
}
private void heapSort(int[] nums) {
if (nums == null || nums.length == 0) {
return;
}
int n = nums.length;
// 从最后一个非叶子节点开始,逐步构建大根堆
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(nums, n, i);
}
// 逐一交换堆顶元素和末尾元素,调整堆
for (int i = n - 1; i > 0; i--) {
swap(nums, 0, i);
heapify(nums, i, 0);// 顶部元素向下沉
}
}
private void heapify(int[] nums, int n, int i) {
int largest = i;
int left = i * 2 + 1;
int right = i * 2 + 2;
// 选出子节点里最大的记录在 largest 里,供后面交换
if (left < n && nums[left] > nums[largest]) {
largest = left;
}
if (right < n && nums[right] > nums[largest]) {
largest = right;
}
// 交换后,继续对交换的位置进行判断
if (largest != i) {
swap(nums, i, largest);
heapify(nums, n, largest);// 递归
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
21. 调整数组顺序使奇数位于偶数前面
java
package Sort;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class OddBeforeEven {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] str = br.readLine().split(" ");
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(str[i]);
}
OddBeforeEven test = new OddBeforeEven();
System.out.println(Arrays.toString(test.reOrderArray(nums)));
}
public int[] reOrderArray(int[] array) {
// write code here
int oddNumber = 0;
int n = array.length;
for (int i = 0; i < n; i++) {
if (array[i] % 2 == 1) oddNumber++;
}
int[] res = new int[n];
for (int i = 0, j = oddNumber, k = 0; k < n; k++) {
if (array[k] % 2 == 1) res[i++] = array[k];
else res[j++] = array[k];
}
return res;
}
}
45. 把数组排成最小的数
java
package Sort;
import java.util.Arrays;
// ====================== 核心思路 ======================
// 贪心思想:自定义排序
//
// 对于两个数字 x 和 y:不比较 x 和 y 本身大小,而是比较 x+y 和 y+x
// 如果 x+y < y+x,那么 x 应该排在 y 前面
//
// 举例:3 和 32
// 比较:"332" 和 "323",因为"323" 更小,所以 32 应该排在 3 前面
//
// 时间复杂度:O(nlogn)
// 空间复杂度:O(n)
// ======================================================
public class MinNumberFromArray {
public String PrintMinNumber(int[] numbers) {
// write code here
if (numbers == null || numbers.length == 0) return "";
String[] numberString = new String[numbers.length];
for (int i = 0; i < numbers.length; i++) {
numberString[i] = numbers[i] + "";
}
Arrays.sort(numberString, (o1, o2) -> (o1 + o2).compareTo(o2 + o1));
StringBuilder sb = new StringBuilder();
for (String s : numberString) {
sb.append(s);
}
return sb.toString();
}
public static void main(String[] args) {
MinNumberFromArray test = new MinNumberFromArray();
int[] numbers = new int[]{3, 32, 321};
System.out.println(test.PrintMinNumber(numbers));
}
}
51. 数组中的逆序对
java
package Sort;
// ====================== 核心思路 ======================
// 题目:数组中的逆序对
// 解法:归并排序 + 逆序对统计
// 核心思想:在 merge 过程中统计跨区间逆序对
//
// 当 nums[l1] > nums[l2],由于左右两部分已经分别有序,说明:
// nums[l1...mid] 都 > nums[l2]
// 所以一次性增加mid - l1 + 1
//
// 时间复杂度:O(n log n)
// 空间复杂度:O(n)
// ======================================================
public class InversePairs {
private long cnt = 0;
public int inversePairs(int[] nums) {
// write code here
mergeSort(nums, 0, nums.length - 1);
return (int) (cnt % 1000000007);
}
private void mergeSort(int[] nums, int left, int right) {
if (left >= right) return;
int mid = (left + right) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, right, mid);
}
private void merge(int[] nums, int left, int right, int mid) {
int l1 = left, l2 = mid + 1, k = 0;
int[] res = new int[right - left + 1];
while (l1 <= mid && l2 <= right) {
if (nums[l1] <= nums[l2]) {
res[k++] = nums[l1++];
} else {
res[k++] = nums[l2++];
cnt += mid - l1 + 1;
}
}
while (l1 <= mid) res[k++] = nums[l1++];
while (l2 <= right) res[k++] = nums[l2++];
for (int i = 0; i < res.length; i++) {
nums[left + i] = res[i];
}
}
public static void main(String[] args) {
int[] nums = new int[]{364, 637, 341, 406, 747, 995, 234, 971, 571, 219, 993, 407, 416, 366, 315, 301, 601, 650, 418, 355, 460, 505, 360, 965, 516, 648, 727, 667, 465, 849, 455, 181, 486, 149, 588, 233, 144, 174, 557, 67, 746, 550, 474, 162, 268, 142, 463, 221, 882, 576, 604, 739, 288, 569, 256, 936, 275, 401, 497, 82, 935, 983, 583, 523, 697, 478, 147, 795, 380, 973, 958, 115, 773, 870, 259, 655, 446, 863, 735, 784, 3, 671, 433, 630, 425, 930, 64, 266, 235, 187, 284, 665, 874, 80, 45, 848, 38, 811, 267, 575};
InversePairs test = new InversePairs();
System.out.println(test.inversePairs(nums));
}
}