【2023/2/27~2/28 Leetcode】二分搜索+带权重的随机选择算法+田忌赛马+常数时间删除

学习链接:

1. 在排序数组中查找元素的第一个和最后一个位置

题目来源:在排序数组中查找元素的第一个和最后一个位置
题解:

//解法1
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                right=mid-1;
            }
            else if(nums[mid]<target){
                left=mid+1;
            }
            else if(nums[mid]>target){
                right=mid-1;
            }
        }
        if(left==nums.size()) return vector<int>{-1,-1};
        int left2=0,right2=nums.size()-1;
        while(left2<=right2){
            int mid2=left2+(right2-left2)/2;
            if(nums[mid2]==target){
                left2=mid2+1;
            }
            else if(nums[mid2]<target){
                left2=mid2+1;
            }
            else if(nums[mid2]>target){
                right2=mid2-1;
            }
        }
        if(left2<1) return vector<int>{-1,-1};
        return (nums[left]==target&&nums[left2-1]==target)?vector<int>{left,right2}:vector<int>{-1,-1};
    }
};
//官方解法
class Solution { 
public:
    int binarySearch(vector<int>& nums, int target, bool lower) {
        int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size();
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target || (lower && nums[mid] >= target)) {
                right = mid - 1;
                ans = mid;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
            return vector<int>{leftIdx, rightIdx};
        } 
        return vector<int>{-1, -1};
    }
};

2. 按权重生成随机数

题目来源:剑指 Offer II 071. 按权重生成随机数
题解:

class Solution {
public:
    vector<int> prefix;
    int total = 0;
    Solution(vector<int>& w) {
        prefix.push_back(0);
        for(int i = 0; i < w.size(); i++){
            total += w[i];
            prefix.push_back(total);//填充前缀和数组
        }
        srand((unsigned)time(NULL));//设置随机数种子
    }
    int pickIndex() {
        int random = (rand()%(total - 1 + 1)) + 1;//生成闭区间[1,total]范围内的一个随机数
        return find(random);//调用二分查找加速
    }
    int find(int target){
        int l = 0;
        int r = prefix.size() - 1;
        while(l <= r){
            int mid = (l + r) >> 1;
            if(prefix[mid] == target) return mid - 1;
            else if(prefix[mid] < target) l = mid + 1;
            else r = mid - 1;
        }
        return l - 1;
    }
};
/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(w);
 * int param_1 = obj->pickIndex();
 */

3. 在D天内送达包裹的能力

题目来源1011. 在 D 天内送达包裹的能力
知识点:【STL】

  • max_element()
  • accumulate()

题解:

class Solution {
public:
    int shipWithinDays(vector<int>& weights, int days) {
        int left=*max_element(weights.begin(),weights.end());
        int right=accumulate(weights.begin(),weights.end(),0);
        while(left<right){
            int mid=left+(right-left)/2;
            int need=1,cur=0;
            for(int weight:weights){
                if(cur+weight>mid){
                    need++;
                    cur=0;
                }
                cur+=weight;
            }
            if(need<=days){
                    right=mid;
                }
                else
                    left=mid+1;
        }
        return left;
    }
};

4.分割数组的最大值

题目来源410. 分割数组的最大值
题解:

class Solution {
public:
    bool check(vector<int>& nums, int x, int m) {
        long long sum = 0;
        int cnt = 1;
        for (int i = 0; i < nums.size(); i++) {
            if (sum + nums[i] > x) {
                cnt++;
                sum = nums[i];
            } else {
                sum += nums[i];
            }
        }
        return cnt <= m;
    }
    int splitArray(vector<int>& nums, int k) {
        long long left=*max_element(nums.begin(),nums.end());
        long long right=accumulate(nums.begin(),nums.end(),0);
        while(left<right){
            long long mid=left+(right-left)/2;
            if(check(nums,mid,k))
                right=mid;
            else 
                left=mid+1;
        }
        return left;
        
    }
};

5.田忌赛马

int[] advantageCount(int[] nums1, int[] nums2) {
    int n = nums1.length;
    // 给 nums2 降序排序
    PriorityQueue<int[]> maxpq = new PriorityQueue<>(
        (int[] pair1, int[] pair2) -> { 
            return pair2[1] - pair1[1];
        }
    );
    for (int i = 0; i < n; i++) {
        maxpq.offer(new int[]{i, nums2[i]});
    }
    // 给 nums1 升序排序
    Arrays.sort(nums1);

    // nums1[left] 是最小值,nums1[right] 是最大值
    int left = 0, right = n - 1;
    int[] res = new int[n];

    while (!maxpq.isEmpty()) {
        int[] pair = maxpq.poll();
        // maxval 是 nums2 中的最大值,i 是对应索引
        int i = pair[0], maxval = pair[1];
        if (maxval < nums1[right]) {
            // 如果 nums1[right] 能胜过 maxval,那就自己上
            res[i] = nums1[right];
            right--;
        } else {
            // 否则用最小值混一下,养精蓄锐
            res[i] = nums1[left];
            left++;
        }
    }
    return res;
}

6.优势洗牌【不太懂捏】

题目来源870. 优势洗牌
题解:

class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size(),ids[n];
        vector<int> ans(n);
        sort(nums1.begin(),nums1.end());
        iota(ids,ids+n,0);
        sort(ids, ids + n, [&](int i, int j) { return nums2[i] < nums2[j]; });
        int left=0,right=n-1;
        for(int x:nums1){
            ans[x>nums2[ids[left]]?ids[left++]:ids[right--]]=x;
        }
        return ans;
    }
};

7.O(1) 时间插入、删除和获取随机元素

题目来源380. O(1) 时间插入、删除和获取随机元素
题解:

class RandomizedSet {
public:
    vector<int> nums;
    unordered_map<int,int> idx;
    RandomizedSet() {

    }
    
    bool insert(int val) {
        if(idx.count(val))
            return false;
        idx[val]=nums.size();
        nums.push_back(val);
        return true;
    }
    
    bool remove(int val) {
        if(idx.count(val)){
            int index=idx[val];
            idx[nums.back()]=index;
            swap(nums[index],nums.back());
            nums.pop_back();
            idx.erase(val);
            return true;
        }
        else
            return false;
    }
    
    int getRandom() {
        return nums[rand()%nums.size()];
    }
};

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet* obj = new RandomizedSet();
 * bool param_1 = obj->insert(val);
 * bool param_2 = obj->remove(val);
 * int param_3 = obj->getRandom();
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值