笔记1 第10课 排序算法——数组的相对排序,合并区间,快速选择算法,翻转对计数——极客时间算法

之前收藏了极客时间的算法训练营3期 共21课,计划每一课写博客来记录学习,主要形式为

方法类型1

题1

题解

题2

题解

方法类型2

题1

题解

……

题目大体来自leetcode 和 acwing

主要记录和理解代码,所以基本完全搬运了视频题解代码,

个人学习感受体现在大致思路的总结和注释上。


第一题

1122. 数组的相对排序

本题可以用hash_map来标记rk值,也可以使用计数排序

1.hash + 快排

class Solution {
public:
    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        for (int i = 0; i < arr2.size(); i++) {
            arr2Orders[arr2[i]] = i;
        }
        sort(arr1.begin(), arr1.end(), [&](int A, int B) {
            int rkA = arr2Orders.find(A) != arr2Orders.end() ? arr2Orders[A] : arr2.size();
            int rkB = arr2Orders.find(B) != arr2Orders.end() ? arr2Orders[B] : arr2.size();
            return rkA < rkB || (rkA == rkB && A < B);
        });
        return arr1;
    }
private:
    unordered_map<int, int> arr2Orders;
};

2.计数

class Solution {
public:
    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        vector<int> cnt(1001, 0);
        for (int num : arr1) {
            cnt[num]++;
        }
        vector<int> ans;
        for (int val : arr2) {
            while (cnt[val] > 0) {
                ans.push_back(val);
                cnt[val]--;
            }
        }
        for (int i = 0; i < 1001; i++) {
            while (cnt[i] > 0) {
                ans.push_back(i);
                cnt[i]--;
            }
        }
        return ans;
    }
private:
};

第二题

56. 合并区间

本题使用双指针,其实对于数组的排序只需要排序开始结点即可,

也可以使用差分,用前缀和来表示有效。

遇到可以连接上的左端,就更新最大的右端,否则将已有区间加入答案

1.双指针

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort (intervals.begin(), intervals.end(), 
        [] (const vector<int>& A, const vector<int>& B){
            return A[0] < B[0] || (A[0] == B[0] && A[1] < B[1]);
        });
        int farthest = -1;
        int start = -1;
        vector<vector<int>> ans;
        for (vector<int> interval : intervals) {
            if (interval[0] <= farthest) {
                farthest = max(farthest, interval[1]);
            }
            else {
                if (start != -1) 
                    ans.push_back({start, farthest});
                start = interval[0];
                farthest = interval[1];
            }
        }
        //if (start != -1) 
            ans.push_back({start, farthest});
        return ans;
    }
};

2.差分

将差分事件数组排序

{3, 1}代表在3的位置开始

{6,-1}代表在5也就是( 6 - 1)的位置结束,差分应该先算结束再算开始,正好按照-1到1的顺序排序了。

算答案就是算当前缀和为0时,记录答案。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<pair<int, int>> events;
        for (vector<int> interval : intervals) {
            events.push_back({interval[0], 1});
            events.push_back({interval[1] + 1, -1});
        }
        sort (events.begin(), events.end());
        int covering = 0;
        int start;
        vector<vector<int>> ans;
        for (const pair<int, int>& event : events) {
            if (covering == 0) start = event.first;
            covering += event.second;
            if (covering == 0) {
                ans.push_back({start, event.first - 1});
            }
        }
        return ans;
    }
};

第三题

​​​​​​215. 数组中的第K个最大元素

快速选择算法,是快排的一半

对于pivot的选择,需要保证返回的是pivot的位置,在函数相应位置已经标注

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return quickSort(nums, 0, nums.size() - 1, nums.size() - k);
    }
private:
    int quickSort (vector<int>& nums, int l, int r, int index) {
        if (l >= r) return nums[l];
        int pivot = partition(nums, l, r);
        if (index <= pivot) return quickSort(nums, l, pivot, index);
        else return quickSort(nums, pivot + 1, r, index);
    }
    int partition(vector<int>& q, int l, int r) {
        int pivot = l + rand() % (r - l + 1);
        int pivotVal = q[pivot];
        while (l <= r) {
            while (q[l] < pivotVal) l++;
            while (q[r] > pivotVal) r--;
            //函数返回的是pivot所在的位置,所以当l = r时要进入判断r的位置是否合理
            if (l == r) break;
            if (l < r) {
                int tmp = q[l];
                q[l] = q[r];
                q[r] = tmp;
                l++, r--;
            }
        }
        return r;
    }
};

第四题

493. 翻转对

归并排序的过程中,计数这种特殊逆序对。

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        mergeSort(nums, 0, nums.size() - 1);
        return ans;
    }
private:
    int ans = 0;
    void mergeSort (vector<int>& q, int l, int r) {
        if (l >= r) return;
        int mid = (l + r) >> 1;
        mergeSort(q, l, mid);
        mergeSort(q, mid + 1, r);
        int j = mid;
        for (int i = l; i <= mid; i++) {
            while (j < r && q[i] > 2l * q[j + 1]) j++;
            ans += j - mid;
        }
        int i = l;
        j = mid + 1;
        vector<int> tmp;
        while (i <= mid && j <= r) {
            if (q[i] <= q[j]) tmp.push_back(q[i++]);
            else tmp.push_back(q[j++]);
        }
        while (i <= mid) tmp.push_back(q[i++]);
        while (j <= r) tmp.push_back(q[j++]);
        for (int i = l, k = 0; i <= r; i++) {
            q[i] = tmp[k++];
        }
    }

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值