Leetcod 分治算法
Leetcode 215
题目描述:
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
解法①:堆
思路:创建一个大顶堆,并保持堆的大小小于等于K。堆内的排序从堆顶递增,最后的堆顶就是所求。
时间复杂度:O(N logK):N 对N个数组插入 logK:堆的插入是二分查找
空间复杂度:O(K);
解法②:快速选择
我的思路:寻找第K大,则是找第length-K小。并不需要把数组排序,因为我们对于第K大左侧顺序,第K大右侧顺序不敢兴趣。只要找到一个数,它的左侧有length-k-1比它小;它的右侧有k-1个比它大即可
题解思路:
随机选择一个枢轴;使用划分算法将枢轴放在数组中的合适位置pos。将小于数周的元素移到左边,大于等于枢轴移到右边;比较pos和N-K,以决定在那边继续递归处理。
代码:
public class Solution {
public int FindKthLargest(int[] nums, int k) {
int left=0,right=nums.Length-1;int target=nums.Length-k;
return quickselect(left,right,target, ref nums);
}
int quickselect(int left,int right,int target, ref int []nums)//递归运算
{
if(left==right) return nums[left];//只剩下一种可能性
Random random=new Random();
int pivot_index=left+random.Next(right-left);//随机选择枢轴,在left-right的范围内
pivot_index=partition(left,right,pivot_index,ref nums);//获得序号
if(pivot_index==target) return nums [pivot_index];
else if(target<pivot_index) return quickselect(left,pivot_index-1,target,ref nums);//在左边继续找
else if(target>pivot_index) return quickselect(pivot_index+1,right,target,ref nums);
return 0;
}
int partition(int left,int right,int target,ref int[] nums)//进行排序
{
int pivot=nums[target];//找出枢轴对应的值
swap(target,right,ref nums);//把枢轴的值放到最后,这是为了保证不至于在枢轴前面出现比枢轴大的值。比如说 小小小大等小小大。-》小小小小小大等大。
for(int i=left;i<=right;i++)
if(nums[i]<pivot) {swap(left,i,ref nums); left++;}//假如都是小于,则left会一直等于i;等到有大于的,left会一直指向大于的数,直到拍到后面
swap(right,left,ref nums);//最后把枢轴给换到中间的地方
return left;//枢轴的序号
}
void swap(int i,int j,ref int []nums)//进行对调
{
int t=nums[i];
nums[i]=nums[j];
nums[j]=t;
}
}
最快的方法:
public class Solution {
int[] nums;
public int FindKthLargest(int[] nums, int k) {
// return nums.OrderByDescending(e => e).ElementAt(k - 1);
this.nums = nums;
var length = nums.Length;
return QuickSelect(0, length - 1, length - k);
}
private int QuickSelect(int left, int right, int kthSmallest) {
if (left == right) return nums[left];
var pivotIndex = new Random().Next(right - left) + left;
pivotIndex = Partition(left, right, pivotIndex);
if (pivotIndex == kthSmallest) return nums[pivotIndex];
else if (pivotIndex > kthSmallest) return QuickSelect(left, pivotIndex - 1, kthSmallest);
else return QuickSelect(pivotIndex + 1, right, kthSmallest);
}
private int Partition(int left, int right, int pivotIndex) {
var pivotValue = nums[pivotIndex];
Swap(right, pivotIndex);
pivotIndex = left;
for (int i = left; i <= right; i++) {
if (nums[i] < pivotValue) {
Swap(i, pivotIndex);
pivotIndex++;
}
}
Swap(pivotIndex, right);
return pivotIndex;
}
private void Swap(int left, int right) {
var temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
不同之处:它把nums提到了class内,这样就不用一直传递nums,在return哪里,它直接用了else,不用再加个return 0
Leetcode 10.09
题目描述:
给定M×N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
Leetcode 973
题目描述:
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
(这里,平面上两点之间的距离是欧几里德距离。)
你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。
示例 1:
输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释:
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]