给定整数数组 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
使用快速排序进行快速查找
class Solution {
public:
// 快速排序
int Quick_Sort(vector<int>& arr, int begin, int end, int k){
if(begin == end) return arr[begin];
int tmp = arr[begin];
int i = begin;
int j = end;
while(i != j){
while(arr[j] <= tmp && j > i)
j--;
while(arr[i] >= tmp && j > i)
i++;
if(j > i){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[begin] = arr[i];
arr[i] = tmp;
if(i+1 == k) return arr[i];
else if(i+1 > k) return Quick_Sort(arr, begin, i-1, k);
else return Quick_Sort(arr, i+1, end, k);
}
int findKthLargest(vector<int>& nums, int k) {
return Quick_Sort(nums,0,nums.size()-1,k);
}
};
关于快排,在循环结束条件的设置上有两种方式,一种为两个指针相遇即(i == j)为结束状态,此情况下,可以将双指针的移动收敛约束到一个位置,方便类似二分查找、快排定位等类似的定位功能上,也方便灵活处理更多的情况,相比之下,另一种交错结束状态,即(i < j),此种结束状态通常用于无需定位查找,只需要排序或者其他类似操作的情况,当然,此情况也可以用于定位,但是对于究竟使用 i 还是 j 的位置需要根据实际情况判断,因此,个人相对来说更喜欢相遇的结束状态
下面是两种情况下的快排代码:
void Quick_Sort(vector<int>& arr, int begin, int end){
if(begin == end) return ;
int tmp = arr[begin];
int i = begin;
int j = end;
while(i != j){
while(arr[j--] <= tmp && j > i)
while(arr[i++] >= tmp && j > i)
if(j > i){
swap(arr[i],arr[j]);
}
}
arr[begin] = arr[i];
arr[i] = tmp;
Quick_Sort(arr, begin, i-1);
Quick_Sort(arr, i+1, end);
}
void Quick_Sort2(int *arr, int begin, int end) {
if (begin >= end) return;
int x = arr[begin], i = begin, j = end; //定义初始化分界点和左右指针
while (i < j) {
while (arr[j] > x) j--;
while (arr[i] < x) i++; //移动左右指针
if (i < j) swap(arr[i], arr[j]);
}
Quick_Sort2(arr, begin, j); //递归处理左右两段
Quick_Sort2(arr, j + 1, end);
}
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5]
输入:head = [1,2,3,4,5], k = 3 输出:[3,2,1,4,5]
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
pair<ListNode*,ListNode*> reverse(ListNode* head,ListNode* tail){
// 递归反转链表 返回链表的头尾节点
if (head == tail) return {head, tail};
auto [newHead, newTail] = reverse(head->next, tail);
head->next->next = head;
head->next = nullptr;
return {newHead, head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
// 取出K个节点,不足则直接返回
ListNode* hair = new ListNode();
hair->next = head;
ListNode* pre = hair;
ListNode* p = head;
while(p){
// 移动尾结点,判断剩余结点是否有K个
ListNode* tail = pre;
for(int i=0;i<k;i++){
tail = tail->next;
if(!tail) return hair->next;
}
ListNode* nextHead = tail->next;
// 翻转链表并接入原链表
auto [newHead, newTail] = reverse(p, tail);
pre->next = newHead;
newTail->next = nextHead;
pre = newTail;
p = nextHead;
}
return hair->next;
}
};
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
由于需要剔除不重复的三元组,且本身时间复杂度也并不小,因此在剪枝方面需要注意很多细节
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int len = nums.size();
sort(nums.begin(),nums.end());
for(int first=0;first<len-2;first++){
if(nums[first] > 0) break;
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int second = first + 1;
int third = len - 1;
while(second < third){
if(nums[second] + nums[third] == -nums[first]){
vector<int> tmp = {nums[first],nums[second],nums[third]};
ans.push_back(tmp);
while(second < third && nums[second]==nums[second+1])
second++;
while(second < third && nums[third]==nums[third-1])
third--;
}
if(nums[second] + nums[third] > -nums[first])
{
third--;
}
else
{
second++;
}
}
}
return ans;
}
};
另外一种消除重复三元组的方法就是使用set的数据结构,但是,由于unordered_set 无法将vector作为key值,但是set可以,但是set的自动排序会使得原本剪枝的复杂度再次提升而导致时间超时,下面仅为一种思路想法,实际运行时间是超时的(如果将上面的剪枝部分加入也是可以通过的)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> ans;
int len = nums.size();
sort(nums.begin(),nums.end());
for(int first=0;first<len-2;first++){
int second = first + 1;
int third = len - 1;
while(second < third){
if(nums[second] + nums[third] == -nums[first]){
vector<int> tmp = {nums[first],nums[second],nums[third]};
ans.insert(tmp);
}
if(nums[second] + nums[third] > -nums[first])
{
third--;
}
else
{
second++;
}
}
}
vector<vector<int>> res;
for(auto it:ans){
res.push_back(it);
}
return res;
}
};