【算法】堆排之 215.数组中的第K个最大元素(medium)

 系列专栏

双指针

模拟算法

分治思想


目录

1、题目链接

2、题目介绍

 3、解法

解题思路

排序方法的选择:

构建小堆:

提取第 k 个最大元素:

4、代码


1、题目链接

215. 数组中的第K个最大元素 - 力扣(LeetCode)

2、题目介绍

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:
[3,2,1,5,6,4],
k = 2
输出: 5

示例 2:

输入:

[3,2,3,1,2,4,5,5,6],
k = 4
输出: 4

提示:

1 <= k <= nums.length <= 105

-104 <= nums[i] <= 104

 3、解法

解题思路

  1. 排序方法的选择

    • 虽然直观上可能会想到对整个数组进行排序然后直接取第 k 个元素,但标准的排序算法(如快速排序、归并排序等)的平均时间复杂度是 O(n log n),不满足题目要求的 O(n)。
    • 尝试了快排,但是会超时。
    • 也可以选择快速选择算法,进行对问题的解决。
  2. 构建小堆

    •  首先,从最后一个非叶子节点((数组长度-2)/2  )开始调整(使用 Adjust Down),以确保每个父节点的值都大于其子节点的值。
      • 这个过程称为堆化(Heapify),它将数组转换为一个最大堆。
  3. 提取第 k 个最大元素

    • 由于最大堆的根节点是数组中的最大值,我们可以通过交换根节点与最后一个元素,并减小堆的大小(即不考虑最后一个元素),然后重新调整新的根节点以保持堆的性质。
    • 重复这个过程 k-1 次后,根节点就会是第 k 个最大的元素。

4、代码

class Solution {
public:
	

	//向下调整
	//降序版
	void AdjustDown(vector<int>& nums, int n, int parent)
	{
		//子节点必须在不越界。 child < nums.size()
		int child = parent * 2 + 1;

		while (child < n)
		{
			// 确认child指向小的那个孩子
			if (child + 1 < n && nums[child + 1] < nums[child])
			{
				++child;
			}

			if (nums[parent] > nums[child])
			{
				swap(nums[parent], nums[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
				break;
		}
	}

	//降序建小堆
	void HeapSort(vector<int>& nums) {

		//从叶子结点建堆
		for (int i = (nums.size() - 1 - 1) / 2; i >= 0; i--)
		{
			AdjustDown(nums, nums.size(), i);
		}

		int end = nums.size() - 1;
		while (end > 0)
		{
			swap(nums[0], nums[end]);
			AdjustDown(nums, end, 0);
			--end;
		}
	}

	int findKthLargest(vector<int>& nums, int k) {
		HeapSort(nums);
		return nums[k-1];
	}
};

💗感谢阅读!💗

寻找两个正序数组的中位数可以使用归并的方式,合并两个有序数组,得到一个大的有序数组。然后找到大的有序数组的中间位置的元素,即为中位数。另一种方法是使用双指针的方式,维护两个指针,初始时分别指向两个数组的下标0的位置。每次将指向较小值的指针后移一位(如果一个指针已经到达数组末尾,则只需要移动另一个数组的指针),直到到达中位数的位置。这样可以在O(log(m+n))的时间复杂度内找到中位数。 具体步骤如下: 1. 初始化指针p1和p2分别指向两个数组的起始位置0。 2. 判断两个指针所指的元素大小,较小的元素所在的指针后移一位,直到其中一个指针到达数组末尾。 3. 若两个数组的长度之和为奇数,那么中位数即为当前指针指向的元素; 若两个数组的长度之和为偶数,那么中位数为当前指针指向的元素与其下一个元素的平均值。 4. 返回中位数作为结果。 需要注意的是,为了保证时间复杂度为O(log(m+n)),在每次移动指针时,应该移动的步数应该是当前指针所在数组长度的一半,即k/2,其中k为两个数组的长度之和。 以下是一个示例代码,用于说明上述方法的实现: ``` int findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length; int n = nums2.length; int total = m + n; int middle = total / 2; int p1 = 0, p2 = 0; int prev = 0, curr = 0; for (int i = 0; i <= middle; i++) { prev = curr; if (p1 < m && (p2 >= n || nums1[p1 < nums2[p2])) { curr = nums1[p1++]; } else { curr = nums2[p2++]; } } if (total % 2 == 0) { return (prev + curr) / 2; } else { return curr; } } ``` 该方法可以在O(log(m+n))的时间复杂度内找到两个正序数组的中位数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [算法:寻找两个正序数组的中位数。](https://blog.csdn.net/en_joker/article/details/107179641)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [寻找两个正序数组的中位数](https://blog.csdn.net/wulila/article/details/124483500)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值