代码题(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;
    }
};

 

posted @ 2021-05-07 00:18  深度机器学习  阅读(123)  评论(0编辑  收藏  举报