informasi kontak saya
Surat[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Kata Pengantar: Artikel ini memberikan jawaban terperinci atas beberapa keraguan tentang pembelajaran awal algoritma pengurutan cepat, dan menyediakan versi optimal dari algoritma pengurutan cepat dasar.
Inti dari algoritma quick sort adalah分治思想
,Strategi memecah belah dan menaklukkan dibagi menjadi tiga langkah berikut:
Diterapkan pada algoritma pengurutan cepat:
Kode kunci untuk penyortiran cepat adalah如何根据基准元素划分数组区间(parttion)
, ada banyak metode dekomposisi, hanya satu metode yang disediakan di sini.挖坑法
Kode:
class Solution {
public int[] sortArray(int[] nums) {
quick(nums, 0, nums.length - 1);
return nums;
}
private void quick(int[] arr, int start, int end) {
if(start >= end) return;// 递归结束条件
int pivot = parttion(arr, start, end);
// 递归解决子问题
quick(arr, start, pivot - 1);
quick(arr, pivot + 1, end);
}
// 挖坑法进行分解
private int parttion(int[] arr, int left, int right) {
int key = arr[left];
while(left < right) {
while(left < right && arr[right] >= key) right--;
arr[left] = arr[right];
while(left < right && arr[left] <= key) ++left;
arr[right] = arr[left];
}
arr[left] = key;
return left;
}
}
Jawaban terperinci:
1.Mengapastart>=end
Apakah ini kondisi akhir dari rekursi?
Dekomposisi sub-masalah secara terus menerus. Ukuran akhir dari sub-masalah adalah 1, yaitu hanya ada satu elemen. Tidak perlu melanjutkan dekomposisi saat ini. Penunjuk awal dan akhir menunjuk ke elemen yang sama waktu.
2. Mengapa yang kanan harus didahulukan daripada yang kiri?
Itu tergantung pada siapa yang pergi duluan
基准元素的位置
,Pada kode di atas, elemen dasar (kunci) adalah elemen paling kiri jika dipindahkan terlebih dahululeft
, left pertama-tama menemukan elemen yang lebih besar dari elemen dasar, lalu mengeksekusiarr[right] = arr[left]
, karena tidak menabungarr[right]
, elemen ini akan hilang
Jika Anda ke kanan terlebih dahulu, ke kanan terlebih dahulu akan menemukan elemen yang lebih kecil dari elemen dasar, lalu mengeksekusiarr[left]=arr[right]
, karena yang kiri saat ini belum bergerak, masih berupa pivot, namun pivot tersebut sudah kita simpan dengan menggunakan kunci.
3.Mengapa arr[right]>=key?>Apakah tidak mungkin?
Lebih besar dari atau sama dengan terutama untuk pemrosesan
重复元素问题
Misalnya, ada sebuah array[6,6,6,6,6]
Jika >, penunjuk kanan tidak akan bergerak, dan penunjuk kiri juga tidak akan bergerak, dan akan terjebak dalam loop tak terbatas.
4. Mengapa disebut metode penggalian lubang?
Ketika penunjuk r bertemu dengan penunjuk pertama
arr[r] = arr[l]
, saat ini posisi l kosong sehingga membentuk lubang.
Ada dua arah pengoptimalan utama:
O(N*logN)
, yaitu kompleksitas waktu terbaik数组分三块
Pada saat yang sama, jika Anda menemukan kasus pengujian khusus (array berurutan atau array terbalik), kompleksitas waktu akan menurun menjadiO(N^2)
Pertama, berdasarkan pertanyaan (urutkan berdasarkan warna) memahami apa itu数组分三块
menganalisa
Kode:
class Solution {
public void sortColors(int[] nums) {
// 分治 --
// 1.定义三指针
int i = 0;// 遍历整个数组
int l = -1, r = nums.length;
while(i < r) {
if(nums[i] == 0) swap(nums,++l,i++);
else if(nums[i] == 1) i++;
else swap(nums,--r,i);
}
return;
}
private void swap(int[] nums,int x,int y) {
int tmp = nums[x]; nums[x] = nums[y]; nums[y] = tmp;
}
}
l,r的起始位置
, elemen pertama dan elemen terakhir menjadi miliknya未处理状态
, jadi `l, r tidak bisa menunjuk ke dua elemen ini dan harus berada di luar interval三个指针去分别维护四个区间
, salah satu intervalnya adalah未处理区间
, saat penunjuk arus terus bergerak, semua interval diproses, dan akhirnya hanya ada tiga interval.Terapkan ide-ide di atas pada快速排序的parttion中
, hasil akhir dibagi menjadi tiga interval
Kode:
class Solution {
// 快速排序优化版
// 分解--解决--合并
public int[] sortArray(int[] nums) {
qsort(nums, 0, nums.length - 1);
return nums;
}
private void qsort(int[] nums, int start, int end) {
if(start >= end) return;// 递归结束条件
// 分解
int pivot = nums[start];
int l = start - 1, r = end + 1, i = start;
while(i < r) {
int cur = nums[i];
if(cur < pivot) swap(nums, ++l, i++);
else if(cur == pivot) ++i;
else swap(nums, --r, i);
}
// [start, l] [l+1, r-1] [r, end]
// 递归解决
qsort(nums, start, l);
qsort(nums, r, end);
}
private void swap(int[] nums,int i, int j) {
int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp;
}
}
2. Pilih nilai dasar secara acak
Pilih secara acak nilai dasar menggunakan angka acak
int pivot = nums[start + new Random().nextInt(end - start + 1)];
// 起始位置 随机产生的偏移量
Selesaikan kode yang ditingkatkan:
class Solution {
// 快速排序优化版
// 分解--解决--合并
public int[] sortArray(int[] nums) {
qsort(nums, 0, nums.length - 1);
return nums;
}
private void qsort(int[] nums, int start, int end) {
if(start >= end) return;// 递归结束条件
// 分解
int pivot = nums[start + new Random().nextInt(end - start + 1)];
int l = start - 1, r = end + 1, i = start;
while(i < r) {
int cur = nums[i];
if(cur < pivot) swap(nums, ++l, i++);
else if(cur == pivot) ++i;
else swap(nums, --r, i);
}
// [start, l] [l+1, r-1] [r, end]
// 递归解决
qsort(nums, start, l);
qsort(nums, r, end);
}
private void swap(int[] nums,int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
Algoritma pemilihan cepat adalah基于快速排序优化版本
Kompleksitas waktuO(N)
Algoritma pemilihan, skenario penggunaannya adalah第K大/前K大
masalah pilihan seperti
01.Elemen terbesar ke-K dalam array
Tautan: https://leetcode.cn/problems/kth-largest-element-in-an-array/
menganalisa
sort
Urutkan lalu kembalikan ke yang terbesar ke-KO(N*logN)
O(logN)
Panggilan tumpukan dihasilkan oleh rekursiSelanjutnya, algoritma seleksi cepat digunakan untuk mengimplementasikanO(N)
Kompleksitas waktu
Kode:
class Solution {
public int findKthLargest(int[] nums, int k) {
return qsort(nums, 0, nums.length - 1, k);
}
private int qsort(int[] nums, int start, int end, int k) {
if(start >= end) return nums[start];
int pivot = nums[start + new Random().nextInt(end - start + 1)];
// 数组分三块 <pivot ==pivot >pivot
int l = start - 1, r = end + 1, i = start;
while(i < r) {
if(nums[i] < pivot) swap(nums, ++l, i++);
else if(nums[i] == pivot) ++i;
else swap(nums, --r, i);
}
// [start, l] [l+1, r - 1] [r, end]
int c = end - r + 1, b = r - 1 - (l + 1) + 1, a = l - start + 1;
// 分情况讨论 进行选择
if(c >= k) return qsort(nums, r, end, k);
else if(b + c >= k) return pivot;
else return qsort(nums, start, l, k - b - c);// 找较小区间的第(k-b-c)大
}
private void swap(int[] arr, int i, int j) {
int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
}
}
O(N)