当前位置:网站首页>剑指offer专项突击版第26天
剑指offer专项突击版第26天
2022-08-11 07:40:00 【_hys】
直接完成所有元素的排序。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.rbegin(),nums.rend());
return nums[k-1];
}
};
通过快排思想,无需完成所有元素的排序获得第k大。(算法过程与二分很类似)
- 快排总是根据基准值将数据分成两堆:一堆大于基准值,一堆小于基准值。
- 所以第 k k k 大肯定在其中一堆,另外一堆就可以忽略了。
- 获得第 k k k 大在当前堆中的相对第几大,传到下一次递归中,直到找到第 k k k 大。
class Solution {
public:
int topk(int l,int r, int k, vector<int> &nums) {
//k表示相对位置
if(l >= r) return nums[l];
int i = l-1, j = r+1;
int mid = nums[i+j>>1];
while(i < j) {
do i++; while(nums[i] > mid);
do j--; while(nums[j] < mid);
if(i < j) swap(nums[i],nums[j]);
}
if(k <= j-l) return topk(l, j, k, nums); //注意这里应该是k <= j-l而不是j
else return topk(j+1, r, k-(j-l+1), nums); //j-l+1是l到j的总长
}
int findKthLargest(vector<int>& nums, int k) {
return topk(0, nums.size()-1, k-1, nums);
}
};
所有排序中归并排序是最适合链表的
1、链表归并自顶向下(递归),空间复杂度 O ( l o g N ) O(logN) O(logN) (多消耗了 l o g N logN logN 个函数栈),这里比较特别的是链表的 m i d mid mid 结点采用快慢指针获取。
class Solution {
public:
ListNode* get_mid(ListNode* head) {
if(!head || !head->next) return head; //空结点或单结点
ListNode *slow = head, *quick = head;
while(quick->next) {
if(quick->next->next) quick = quick->next->next;
else break;
slow = slow->next;
}
auto mid = slow->next; //相当于/2上取整
slow->next = nullptr; //必须断开
return mid;
}
ListNode* sortList(ListNode* head) {
return merge_sort(head, get_mid(head));
}
ListNode* merge_sort(ListNode* l, ListNode *r) {
if(l == r) return l;
ListNode *head = new ListNode(), *tmp = head;
ListNode *i = merge_sort(l,get_mid(l)), *j = merge_sort(r,get_mid(r));
while(i != nullptr && j != nullptr) {
if(i->val < j->val) {
tmp->next = i;
i = i->next;
} else {
tmp->next = j;
j = j->next;
}
tmp = tmp->next;
}
if(i) tmp->next = i;
if(j) tmp->next = j;
return head->next;
}
};
2、链表归并自底向上(迭代),空间复杂度 O ( 1 ) O(1) O(1)
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head == nullptr) {
return head;
}
int length = 0;
ListNode* node = head;
while (node != nullptr) {
length++;
node = node->next;
}
ListNode* dummyHead = new ListNode(0, head);
for (int subLength = 1; subLength < length; subLength <<= 1) {
ListNode* prev = dummyHead, *curr = dummyHead->next;
while (curr != nullptr) {
ListNode* head1 = curr;
//移动subLength长度
for (int i = 1; i < subLength && curr->next != nullptr; i++) {
curr = curr->next;
}
ListNode* head2 = curr->next;
curr->next = nullptr;
curr = head2;
//移动subLength长度
for (int i = 1; i < subLength && curr != nullptr && curr->next != nullptr; i++) {
curr = curr->next;
}
ListNode* next = nullptr; //下一个需要归并的子序列开始位置
if (curr != nullptr) {
next = curr->next;
curr->next = nullptr;
}
ListNode* merged = merge(head1, head2); //返回有序的链表头
prev->next = merged;
while (prev->next != nullptr) {
//接上有序链表
prev = prev->next;
}
curr = next; //curr移动到下一个需要归并的子序列开始位置
}
}
return dummyHead->next;
}
ListNode* merge(ListNode* head1, ListNode* head2) {
//无递归
ListNode* dummyHead = new ListNode(0);
ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
while (temp1 != nullptr && temp2 != nullptr) {
if (temp1->val <= temp2->val) {
temp->next = temp1;
temp1 = temp1->next;
} else {
temp->next = temp2;
temp2 = temp2->next;
}
temp = temp->next;
}
if (temp1 != nullptr) {
temp->next = temp1;
} else if (temp2 != nullptr) {
temp->next = temp2;
}
return dummyHead->next;
}
};
就类似归并排序中的操作,按顺序一个一个合并需要 N N N 次。
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *res = nullptr;
for(int i = 0; i < lists.size(); i++) {
res = merge(res,lists[i]);
}
return res;
}
ListNode* merge(ListNode* h1, ListNode *h2) {
if(!h1) return h2;
ListNode *res = new ListNode(), *tmp = res;
while(h1 && h2) {
if(h1->val < h2->val) {
tmp->next = h1;
tmp = tmp->next;
h1 = h1->next;
} else {
tmp->next = h2;
tmp = tmp->next;
h2 = h2->next;
}
}
if(h1) tmp->next = h1;
if(h2) tmp->next = h2;
return res->next;
}
};
分治合并,只需要 l o g N logN logN 次合并即可。
class Solution {
public:
ListNode* merge_list(ListNode* h1, ListNode *h2) {
if(!h1) return h2;
ListNode *res = new ListNode(), *tmp = res;
while(h1 && h2) {
if(h1->val < h2->val) {
tmp->next = h1;
tmp = tmp->next;
h1 = h1->next;
} else {
tmp->next = h2;
tmp = tmp->next;
h2 = h2->next;
}
}
if(h1) tmp->next = h1;
if(h2) tmp->next = h2;
return res->next;
}
ListNode* merge(vector <ListNode*> &lists, int l, int r) {
if (l == r) return lists[l];
if (l > r) return nullptr;
int mid = (l + r) >> 1;
return merge_list(merge(lists, l, mid), merge(lists, mid + 1, r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge(lists, 0, lists.size() - 1);
}
};
边栏推荐
- Service的两种启动方式与区别
- 零基础SQL教程: 主键、外键和索引 04
- 接口测试的基础流程和用例设计方法你知道吗?
- JRS303-数据校验
- redis operation
- 记录一些遇见的bug——Lombok和Mapstruct的冲突导致,A component required a bean of type ‘com.XXX.controller.converter.
- [Recommender System]: Overview of Collaborative Filtering and Content-Based Filtering
- 流式结构化数据计算语言的进化与新选择
- 1046 划拳 (15 分)
- Dynamic Agent Learning
猜你喜欢
随机推荐
About # SQL problem: how to set the following data by commas into multiple lines, in the form of column display
Pico neo3在Unity中的交互操作
测试用例很难?有手就行
分布式锁-Redission - 缓存一致性解决
Square, multi-power, square root calculation in Tf
Keep track of your monthly income and expenses through bookkeeping
tf.cast(), reduce_min(), reduce_max()
The growth path of a 40W test engineer with an annual salary, which stage are you in?
租房小程序
Find the latest staff salary and the last staff salary changes
项目1-PM2.5预测
1096 大美数 (15 分)
机器学习总结(二)
TF通过feature与label生成(特征,标签)集合,tf.data.Dataset.from_tensor_slices
通过记账,了解当月收支情况
1051 复数乘法 (15 分)
Redis source code: how to view the Redis source code, the order of viewing the Redis source code, the sequence of the source code from the external data structure of Redis to the internal data structu
There may be fields that cannot be serialized in the abnormal object of cdc and sqlserver. Is there anyone who can understand it? Help me to answer
3.2 - classification - Logistic regression
tf.reduce_mean()与tf.reduce_sum()