2021-01-22分治

力扣分治练习

1.数组中第K个最大元素

(1)方法一:堆

 维护一个堆,时间复杂度O(nlogk),调整堆O(logk),空间复杂度O(k) 
1.小根堆:
 堆内只有k容量,一旦超过就把最小的(即队首元素推出),遍历完数组后只剩下最后k大的数,队首元素是第k大数
2.大根堆:
 做k-1次删除后,队首元素即为第k大
  • stl实现
class Solution {
    
    
public:
    
    int findKthLargest(vector<int>& nums, int k) {
    
    
       	//priority_queue<int> a 默认大顶堆 
	    priority_queue<int,vector<int>,greater<int> > heap;//创建一个最小堆 
	    for(int num:nums){
    
    //num是nums[i]不是i
	    
	    	heap.push(num);
	    	if(heap.size()>k)//如果堆中的元素数量大于k,就把最小的推出 
	    	heap.pop();
		}
      
		return heap.top();//返回队首元素 
    }
};
  • 自创建堆
class Solution {
    
    
public:
    int findKthLargest(vector<int>nums,int k){
    
    
			//对前k个元素建成小根堆
			for(int i=0;i<k;i++)
			swim(nums,i);//nums[0]-nums[k-1]是堆,nums[0]是堆首,从小到大 
			
			// 将其后每个元素和堆首元素比较,如果大于,将堆顶去除,加入堆并下沉 
			 for(int i=k;i<nums.size();i++){
    
    
			 	if(nums[i]>nums[0]){
    
    
				 swap(nums[i],nums[0]);//只有前k个数是堆,交换即去除
				 sink(nums,0,k-1);//下沉 
				 } 
			 }
			 return nums[0]; 
	}
void swim(vector<int>& heap,int i){
    
    //从0-i上升式建堆
       if(i<=0)
        return;
    
    int j=(i-1)/2;//父节点 
	while(heap[i]<heap[j]&&i>0){
    
    
		swap(heap[i],heap[j]); 
		i=j;
		j=(i-1)/2;
	} 
	
}
void sink(vector<int>& heap,int i,int N){
    
    //下沉式调整位置 ,N代表heap的容量
       int j=2*i+1;//左孩子节点
	   while(j<=N){
    
    //当左孩子存在时
	      if(j+1<=N&&heap[j+1]<heap[j])
		     j++;//右节点也存在并且右节点比左节点小,j表示右节点 
	   	   if(heap[i]<heap[j]) //父节点比子节点都小,可,tui出循环 
	   	   break;
	   	   swap(heap[i],heap[j]);//大就交换位置 
	   	   i=j;
	   	   j=2*i+1;
			
	   } 
	
}
    
};

(2)方法二:快排

快排适合在确定数据量时寻找第k大的数,如果是动态数据流只能由堆排序算法

1.排好所有的数从小到大,找nums[n-k]为第k大


int partition(int A[],int left,int right){
    
    //排A[right]的数 
	int i=left,j=right,temp=A[right];
	
		while(i!=j){
    
    
			while(i<j&&A[i]<=temp){
    
    
				i++;
			}
			A[j]=A[i];
			while(i<j&&A[j]>temp){
    
    
				j--;
			}
			A[i]=A[j];
		}
		A[i]=temp;
		 
	return i;
} 
void quickSort(int a[],int left,int right){
    
    
	if(left<right){
    
    //意味着至少是两个数,如果只有一个数或者left>right无意义 
		int mid=partition(a,left,right);//最右边的数最终的位置将数组划分为两部分 
		quickSort(a,left,mid-1);//对左区间排序 
		quickSort(a,mid+1,right);//对右区间排序 
		
	}
	return ;
} 

int findKthLargest(int* nums, int numsSize, int k){
    
    
    quickSort(nums,0,numsSize-1);
    return nums[numsSize-k];
}

2.当n-k确定后直接返回

int partition(int A[],int left,int right){
    
    //排A[right]的数 
	int i=left,j=right,temp=A[right];
	
		while(i!=j){
    
    
			while(i<j&&A[i]<=temp){
    
    
				i++;
			}
			A[j]=A[i];
			while(i<j&&A[j]>temp){
    
    
				j--;
			}
			A[i]=A[j];
		}
		A[i]=temp;
		 
	return i;
} 
void quickSort(int a[],int left,int right,int k){
    
    
	if(left<right){
    
    //意味着至少是两个数,如果只有一个数或者left>right无意义 
		int mid=partition(a,left,right);//最右边的数最终的位置将数组划分为两部分
        if(mid==k)
            return ;
		quickSort(a,left,mid-1,k);//对左区间排序 
		quickSort(a,mid+1,right,k);//对右区间排序 
		
	}
	return ;
} 

int findKthLargest(int* nums, int numsSize, int k){
    
    
    quickSort(nums,0,numsSize-1,numsSize-k);
    return nums[numsSize-k];
}

猜你喜欢

转载自blog.csdn.net/weixin_46064382/article/details/110919108
今日推荐