额外题目 | 数组 7-9 *

文章介绍了如何在排序数组中使用二分查找法找到目标元素的第一个和最后一个位置,以及如何实现时间复杂度为O(logn)的解决方案。同时,提供了按奇偶排序数组的两种方法,均具有O(n)的时间复杂度。另外,还涵盖了搜索插入位置的问题,给出了解决策略。
摘要由CSDN通过智能技术生成

本文记录的是刷题过程中的重要概念和笔记。如有侵权,请联系删除。

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

力扣链接(opens new window)

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

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

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

示例 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 ( log ⁡ n ) O(\log n) O(logn) 的算法
一次二分查找再找出两端是O(n)

解决:两次
采用while (left <= right)的写法,区间定义为[left, right],即左闭右闭的区间
找右边的边界:

// 二分查找,寻找target的右边界(不包括target)
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
int getRightBorder(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
    int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
    while (left <= right) { // 当left==right,区间[left, right]依然有效
        int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
        if (nums[middle] > target) {
            right = middle - 1; // target 在左区间,所以[left, middle - 1]
        } else { // 当nums[middle] == target的时候,更新left,这样才能得到target的右边界
            left = middle + 1;
            rightBorder = left;
        }
    }
    return rightBorder;
}
  • 当nums[middle] == target的时候,更新left,这样才能得到target的右边界

C++完整

class Solution {
public:
    int getBorder(vector<int>& nums,int target,int signal){
        // [ )
        // signal: 0--left, 1--right
        int left=0,right=nums.size(),mid=0;
        int res=-1; // initalization: -1 not found
        while(left<right){
            mid=left+(right-left)/2;
            if(nums[mid]>target) right=mid;
            else if(nums[mid]<target) left=mid+1;
            else if(nums[mid]==target && signal==0){
                 right=mid;
                 res=mid;
            }else{
                res=mid;
                left=mid+1;
            }
        }
        return res;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res(2,-1);
        if(nums.size()==0) return res;
        res[0]=getBorder(nums,target,0);
        res[1]=getBorder(nums,target,1);
        return res;
    }
};

总结

  1. 一次不行,试试多次
  2. 找左找右,能否分而治之


922. 按奇偶排序数组II *

力扣题目链接(opens new window)

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。

对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。

你可以返回任何满足上述条件的数组作为答案。

示例:

输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

思路

很多思路,双指针

class Solution {
public:
    vector<int> sortArrayByParityII(vector<int>& nums) {
        int index=0;
        for(int i=1;i<nums.size();i+=2){
            if(nums[i] %2==0){
                swap(nums[i],nums[index]);
                index+=2;
                i-=2;
            }
        }
        return nums;
    }
};

时间复杂度:O(n)
空间复杂度:O(1)
或者

class Solution {
public:
    vector<int> sortArrayByParityII(vector<int>& A) {
        int oddIndex = 1;
        for (int i = 0; i < A.size(); i += 2) {
            if (A[i] % 2 == 1) { // 在偶数位遇到了奇数
                while(A[oddIndex] % 2 != 0) oddIndex += 2; // 在奇数位找一个偶数
                swap(A[i], A[oddIndex]); // 替换
            }
        }
        return A;
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

35.搜索插入位置 *

力扣题目链接(opens new window)

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2
示例 2:

输入: [1,3,5,6], 2
输出: 1
示例 3:

输入: [1,3,5,6], 7
输出: 4
示例 4:

输入: [1,3,5,6], 0
输出: 0

思路

已经做过

[ ) 的区间,分类讨论可知,退出来的时候 left==right ,此时的位置值恰好大于target。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值