• 代码题(65)— 在排序数组中查找元素的第一个和最后一个位置、长度最小的子数组


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

    给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

    如果数组中不存在目标值 target,返回 [-1, -1]。

    进阶:你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

    示例 1:输入:nums = [5,7,7,8,8,10], target = 8

    输出:[3,4]
    示例 2:输入:nums = [5,7,7,8,8,10], target = 6

    输出:[-1,-1]
    示例 3:输入:nums = [], target = 0

    输出:[-1,-1]

    O(logn) 的算法,使用两次二分查找法,第一次找到左边界,第二次调用找到右边界即可,具体代码如下:

    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            vector<int> res(2, -1);
            if(nums.empty())
                return res;
            int low = 0;
            int high = nums.size()-1;
            while(low<high){  
                int mid = (low+high)/2;
                if(nums[mid]>=target) // 查找左边界
                    high = mid;
                else
                    low = mid+1;
            }
            if(nums[low] != target)
                return res;
            res[0] = low;
            low = 0; high = nums.size()-1;
            while(low<high){
                int mid = (low+high+1)/2;
                if(nums[mid]<=target) // 查找右边界,high 需要向上取整
                    low = mid;
                else 
                    high = mid-1;
            }
            res[1] = low;
            return res;
        }
    };

     2、209. 长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 target 。

    找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

    示例 1:输入:target = 7, nums = [2,3,1,2,4,3]

    输出:2
    解释:子数组 [4,3] 是该条件下的长度最小的子数组。
    示例 2:输入:target = 4, nums = [1,4,4]

    输出:1
    示例 3:输入:target = 11, nums = [1,1,1,1,1,1,1,1]

    输出:0

    解法一:这道题目暴力解法当然是 两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2) 。时间复杂度:O(n^2);空间复杂度:O(1)

    class Solution {
    public:
        int minSubArrayLen(int target, vector<int>& nums) {
            int res = INT32_MAX;
            if(nums.empty())
                return res;
            int sum = 0;
            int subLength = 0;
            for(int i=0;i<nums.size();++i){
                sum = 0;
                for(int j=i;j<nums.size();++j){
                    sum += nums[j];
                    if(sum >= target){ // 一旦发现子序列和超过了s,更新result
                        subLength = j-i+1; // 取子序列的长度
                        res = res<subLength?res:subLength;
                        break;// 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                    }
                }
            }
            return res == INT32_MAX?0:res;
        }
    };

     解法二:

    所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

    这里还是以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程:

    class Solution {
    public:
        int minSubArrayLen(int target, vector<int>& nums) {
            int res = INT32_MAX;
            int sum = 0;// 滑动窗口数值之和
            int i = 0;// 滑动窗口起始位置
            int subLength = 0;// 滑动窗口的长度
            for(int j=0;j<nums.size();++j){
                sum += nums[j];
                // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
                while(sum >= target){
                    subLength = j-i+1;// 取子序列的长度
                    res = res<subLength?res:subLength;
                    sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
                }
            }
            // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
            return res == INT32_MAX ? 0 : res;
        }
    };
  • 相关阅读:
    【EF学习笔记11】----------查询中常用的扩展方法
    .NET 扩展方法
    【EF学习笔记10】----------主从表级联操作
    【EF学习笔记09】----------使用 EntityState 枚举标记实体状态,实现增删改查
    【EF学习笔记08】----------加载关联表的数据 显式加载
    【EF学习笔记07】----------加载关联表的数据 贪婪加载
    【EF学习笔记06】----------加载关联表的数据 延迟加载
    Linux内核ROP姿势详解(二)
    见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出
    见微知著(二):解析ctf中的pwn--怎么利用double free
  • 原文地址:https://www.cnblogs.com/eilearn/p/14737494.html
Copyright © 2020-2023  润新知