• 剑指offer专项突击版第26天


    剑指 Offer II 076. 数组中的第 k 大的数字

    直接完成所有元素的排序。

    class Solution {
    public:
        int findKthLargest(vector<int>& nums, int k) {
            sort(nums.rbegin(),nums.rend());
            return nums[k-1];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过快排思想,无需完成所有元素的排序获得第k大。(算法过程与二分很类似)

    1. 快排总是根据基准值将数据分成两堆:一堆大于基准值,一堆小于基准值。
    2. 所以第 k k k 大肯定在其中一堆,另外一堆就可以忽略了。
    3. 获得第 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    剑指 Offer II 077. 链表排序

    所有排序中归并排序是最适合链表的
    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;
        }
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    剑指 Offer II 078. 合并排序链表

    就类似归并排序中的操作,按顺序一个一个合并需要 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;
        }
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    分治合并,只需要 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);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    大数据-hadoop
    (Java岗面试)耗时1月最新整理了20个技术栈的大厂面试题+解析+面经!
    GD32_ADC采样+DMA多通道扫描传输
    Go的优雅退出
    BioVendor游离轻链(κ和λ)Elisa 试剂盒检测步骤
    Vue的侦听器
    笛卡尔积现象
    学习笔记16--V2X技术
    Mysql事物、隔离级别、锁
    MySQL 用户账号管理(Accounts Management)
  • 原文地址:https://blog.csdn.net/hys__handsome/article/details/126275020