HOT100打卡—day5—【二分查找】—23.8.8+19

文章介绍了在不同类型的已排序或旋转数组中使用二分搜索的方法,包括在一维数组、二维矩阵、排序数组中查找元素位置,以及在旋转数组中找到最小值和中位数,展示了高效的算法实现。
摘要由CSDN通过智能技术生成

1 35. 搜索插入位置

35. 搜索插入位置

AC代码:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size()-1;
        while(l < r)
        {
            int mid = (l+r) >> 1;
            if(nums[mid] >= target)r = mid;
            else l = mid + 1;
        }
        if(nums[l] >= target)return l;
        else return l+1;
    }
};

 2 74. 搜索二维矩阵

74. 搜索二维矩阵

一次AC代码:

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        // 先第一列二分再 某一行二分
        int l = 0;
        int r = matrix.size() - 1;
        while(l < r)
        {
            int mid = (l+r) >> 1;
            if(matrix[mid][0] >= target)r = mid;  // 找到大于等于target的第一个
            else l = mid + 1;
        }

        if(matrix[l][0] == target)return 1;
        else if(matrix[l][0] < target)
        {
            // 最后一行
            int i = 0;
            int j = matrix[matrix.size() - 1].size() - 1;
            while(i < j)
            {
                int mid = (i+j) >> 1;
                if(matrix[matrix.size() - 1][mid] >= target)j = mid;  // 找到大于等于target的第一个
                else i = mid + 1;
            }
            if(matrix[matrix.size() - 1][i] == target)return 1;
            else return 0;
        }
        else 
        {
            if(l == 0)return 0;
            int i = 0;
            int j = matrix[l-1].size() - 1;
            while(i < j)
            {
                int mid = (i+j) >> 1;
                if(matrix[l-1][mid] >= target)j = mid;  // 找到大于等于target的第一个
                else i = mid + 1;
            }
            if(matrix[l-1][i] == target)return 1;
            else return 0;
        }
    }
};

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

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

常规的两次二分。AC代码:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        // 二分
        vector<int> ans;
        // 【1】大于等于target的第一个下标
        int l = 0;
        int r = nums.size()-1;
        while(l < r)
        {
            int mid = (l + r) >> 1;
            if(nums[mid] >= target)r = mid;
            else l = mid + 1;
        }

        if(nums.size() == 0 ||  nums[r] != target){
            ans.push_back(-1);
            ans.push_back(-1);
            return ans;
        }
        else ans.push_back(l);
        
        l = 0;
        r = nums.size()-1;
        while(l < r)
        {
            int mid = (l + r + 1) >> 1;
            if(nums[mid] <= target)l = mid;
            else r = mid - 1;
        }
        ans.push_back(l);
        return ans;
    }
};

 4 33. 搜索旋转排序数组(更好的一次二分解法有空补)

33. 搜索旋转排序数组

我O(2*logn)用了两次二分的解法,AC代码:

看了题解其实也可以写成一个二分的,就是O(logn)的解法。有空再补把

class Solution {
public:
    int erfen(vector<int> nums,int l,int r,int target)
    {
        while(l < r)
        {
            int mid = (l+r+1) >> 1;
            if(nums[mid] <= target)l = mid;
            else r = mid - 1;
        }
        if(target == nums[l])return l;
        else return -1;
    }
    int search(vector<int>& nums, int target) {
        // 先O(logn)找到右边升序序列的起点
        int l = 0;
        int r = nums.size()-1;

        if(nums[0] <= nums[nums.size()-1])
        {
            return erfen(nums,l,r,target);
        }
        else{
            while(l < r)
            {
                int mid = (l + r) >> 1;
                if(nums[mid] < nums[0])r = mid;
                else l = mid + 1;
            }
            int ans1 = -1;
            int ans2 = -1;
            if(target >= nums[0] && target <= nums[l-1])ans1 = erfen(nums,0,l-1,target);
            else if(target >= nums[l] && target <= nums[nums.size()-1])ans2 = erfen(nums,l,nums.size()-1,target);

            if(ans1 == -1 && ans2 == -1)return -1;
            else return ans1 == -1?ans2:ans1;

        }
        
    }
};

5 153. 寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值

半暴力,AC:

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums[0] <= nums[nums.size()-1])return nums[0];

        for(int i = 0; i < nums.size();i++)
            if(i+1 < nums.size() && nums[i] > nums[i+1])return nums[i+1];
        
        return 0;
    }
};

解法2——二分:(搬运自题解

竖直虚线左边的数满足 nums[i]≥nums[0]nums[i]≥nums[0]nums[i]≥nums[0],而竖直虚线右边的数满足nums[i]<nums[0]nums[i]< nums[0]nums[i]<nums[0],分界点就是整个数组的最小值。数组具有二分性,所以我们可以二分出最小值的位置。

用了二分,AC代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums[0] <= nums[nums.size()-1])return nums[0];
       int l = 0;
       int r = nums.size()-1;
       while(l < r)
       {
           int mid = (l+r) >> 1;
           if(nums[mid] < nums[0])r=mid;  //找到第一个小于nums[0]的数
           else l = mid+1;
       }
        
        return nums[l];
    }
};

6 4. 寻找两个正序数组的中位数

4. 寻找两个正序数组的中位数

不理解这题怎么标到困难的,我感觉很简单,两个数列都是有序的 就是找第k大数(这个k就是两个数组长度和/2 ,数组长度和按照奇数偶数分类,最后算中位数时候分类讨论,奇数只要第k个数 ,偶数就是k大和它前面那个数的二数平均)就行,只用到了双指针归并排序中间归并的那一步。一次AC代码:(ps:前几天pat也做过两个数列有序的 就是找第k大数的题目)

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) 
    {
        int mid = nums1.size() + nums2.size();
        mid /= 2;

        int i = 0;
        int j = 0;
        int k = 0;
        vector<int> ans;
        while(i < nums1.size() && j < nums2.size() && k <= mid)
        {
            if(nums1[i] <= nums2[j])
            {
                ans.push_back(nums1[i]);
                i++;
                k++;
            }
            else
            {
                ans.push_back(nums2[j]);
                j++;
                k++;
            }
        }
        while(i < nums1.size() && k <= mid)
        {
            ans.push_back(nums1[i]);
            i++;
            k++;
        }
        while(j < nums2.size() && k <= mid)
        {
            ans.push_back(nums2[j]);
            j++;
            k++;
        }

        if((nums1.size() + nums2.size())% 2 == 1) return ans[mid];
        else return (double)(ans[mid]+ans[mid-1])/2;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这行代码通常出现在强化学习中的经验回放缓存中,其中`r`是一个时间步的即时奖励。这行代码的作用是将奖励进行归一化,将奖励的范围缩放到[-1, 1]之间。 具体来说,经验回放缓存通常会保存一些经验元组,每个元组包括当前状态、执行的动作、即时奖励、下一个状态和是否终止等信息。在训练神经网络时,我们需要从缓存中随机采样一批经验元组,并将它们用于训练神经网络。在这个过程中,如果奖励的范围过大,会导致训练不稳定,因此需要将奖励进行归一化。 例如,以下代码使用经验回放缓存来训练一个强化学习智能体: ``` import numpy as np import tensorflow as tf # 定义神经网络和优化器 model = tf.keras.models.Sequential([...]) optimizer = tf.keras.optimizers.Adam(learning_rate=0.001) # 定义经验回放缓存 buffer_s, buffer_a, buffer_r, buffer_s_, buffer_done = [], [], [], [], [] # 采样一批经验元组 batch_size = 32 indices = np.random.choice(len(buffer_r), size=batch_size) batch_s = np.array([buffer_s[i] for i in indices]) batch_a = np.array([buffer_a[i] for i in indices]) batch_r = np.array([buffer_r[i] for i in indices]) batch_s_ = np.array([buffer_s_[i] for i in indices]) batch_done = np.array([buffer_done[i] for i in indices]) # 计算目标值 target = batch_r + (1 - batch_done) * GAMMA * np.amax(model.predict(batch_s_), axis=1) # 计算损失并更新参数 with tf.GradientTape() as tape: pred = tf.reduce_sum(model(batch_s) * tf.one_hot(batch_a, N_ACTIONS), axis=1) loss = tf.keras.losses.mean_squared_error(target, pred) grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) ``` 在上面的例子中,`buffer_r`是一个保存即时奖励的列表。我们将奖励进行归一化,将奖励的范围缩放到[-1, 1]之间。这样可以使得奖励的分布更加稳定,有利于神经网络的训练。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值