1.概述
合并k个排序链表:分而治之,分到区间内只有一个链表,合并区间
二分查找:减而治之,每次搜索范围内元素减少一半
2.快速选择算法
选择最右侧元素为基准点,比基准点小的,交换到左边,比基准点大的,交换到右边
经过一轮过后,左边的是比基准点小的,右边的是比基准点大的,但是我们并不关心其他元素,只关系基准点元素,不用整个数组都排序,时间复杂度:O(n)
/**
* 快速选择算法--分治思想
*/
public class QuickSelect {
static int quick(int[] array, int left, int right, int i) {
//找一个基准点,然后进行排序
int p = partition(array, left, right);//基准点元素索引值
if (p == i) {//找到了
return array[p];
}
//没找到
if (i < p) {//到左边找
return quick(array, left, p - 1, i);
} else {//到右边找
return quick(array, p + 1, right, i);
}
//Arrays.sort(array);//n*log(n)
}
public static void main(String[] args) {
int[] array = {6, 5, 1, 2, 4};
System.out.println(quick(array, 0, array.length - 1, 0));
System.out.println(quick(array, 0, array.length - 1, 1));
System.out.println(quick(array, 0, array.length - 1, 2));
System.out.println(quick(array, 0, array.length - 1, 3));
System.out.println(quick(array, 0, array.length - 1, 4));
}
private static int partition(int[] a, int left, int right) {
//生成left-right范围内的索引
int idx = ThreadLocalRandom.current().nextInt(right - left + 1) + left;//选择随机基准点
swap(a, idx, left);//idx的元素和left元素进行交换
int pv = a[left];
int i = left;//从左向右找大的
int j = right;//从右向左找小的
while (i < j) {
//1.j从右向左找小(等)的
while (i < j && a[j] > pv) {//相当于没找到小的
j--;
}
//2.i从左向右找大的
while (i < j && a[i] <= pv) {//相当于没找到大的
i++;
}
//3.交换位置
swap(a, i, j);
}
swap(a, left, i);
return i;//最终基准点元素排好序后的索引位置
}
private static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
应用 :
Leetcode215
int quickselect(int[] nums, int l, int r, int k) {
if (l == r) return nums[k];
int x = nums[l], i = l - 1, j = r + 1;
while (i < j) {
do i++; while (nums[i] < x);
do j--; while (nums[j] > x);
if (i < j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
if (k <= j) return quickselect(nums, l, j, k);
else return quickselect(nums, j + 1, r, k);
}
public int findKthLargest(int[] _nums, int k) {
int n = _nums.length;
return quickselect(_nums, 0, n - 1, n - k);
}
数组中位数
/**
* 数组中的中位数-快速选择
*/
public class FindMedian {
public static double findMedian(int[] nums) {
if (nums.length % 2 == 1) {//奇数
return QuickSelect.quick(nums, 0, nums.length - 1, nums.length / 2);
} else {//偶数
int x = QuickSelect.quick(nums, 0, nums.length - 1, nums.length / 2);
int y = QuickSelect.quick(nums, 0, nums.length - 1, nums.length / 2 - 1);
return (x + y) / 2.0;
}
}
}
Leetcode50
public static double myPow(double x, long n) {
if (n == 0) {
return 1.0;
}
if (n == 1) {//其实可以不用这个,但是从效率上讲,可以减少一次不必要的递归
return x;
}
//进行优化,不用每次都算,提高运行效率
double v = myPow(x, n / 2);
if (n < 0) {
long p = -n;
return 1 / myPow(x, p);
}
if ((n & 1) == 0) {//偶数
return v * v;
} else {//奇数
return v * v * x;
}
}
Leetcode69
public int mySqrt(int x) {
int i = 1, j = x;
int r = 0;
while (i <= j) {
int m = (i + j) >>> 1;
if (m <= x / m) {
i = m + 1;
r = m;
} else {
j = m - 1;
}
}
return r;
}
Leetcode395
public int longestSubstring(String s, int k) {
if (s.length() < k) {
return 0;
}
int[] counts = new int[26];
char[] chars = s.toCharArray();
for (char c : chars) {
counts[c - 'a']++;
}
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
int count = counts[c - 'a'];
if (count > 0 && count < k) {
int j = i + 1;
while (j < s.length() && counts[chars[j] - 'a'] < k) {
j++;
}
return Integer.max(longestSubstring(s.substring(0,i),k),longestSubstring(s.substring(j),k));
}
}
return s.length();
}