数组

1、一个各不相同元素的数组,求它的一个局部最小值。
局部极小值的定义为:一个值比左右相邻的值都小。

算法:如果o(n)遍历的话很容易求得一个全局最小值。当然是局部最小值。

也可以用二分查找算法,局部最小值一定在两个波峰之间。规定数组两端都是正无穷,那么局部最小值一定在两个波峰之间。可以比较mid与mid+1,如果小于mid+1那么mid+1就是一个波峰,局部最小值在mid前半部分;如果大于mid+1,那么mid就是一个波峰,局部最小值在mid后半部分

同理可以求得局部最大值。

class Solution {
public:
    int halfPeak(vector<int>nums,int start,int end){

        int mid = (start + end ) /2 ;
        //如果mid是首元素,那么大于后一个值就是局部最大值
        if(mid == 0 && nums[mid]>nums[mid+1])
            return mid;
        //如果mid不是首元素,那么大于两边就是局部最大值
        if(mid!=0 && nums[mid]>nums[mid+1] && nums[mid] >nums[mid-1])
            return mid;
        //如果不满足条件,则判断后继续寻找。局部最大肯定在两个波谷之间
        if(nums[mid] <nums[mid+1])
            return halfPeak(nums,mid+1,end);
        else
            return halfPeak(nums,start,mid);
    }
    int findPeakElement(vector<int>& nums) {
        if(nums.size() <2)
            return 0;
        nums.push_back(INT_MIN);
        return halfPeak(nums,0,nums.size()-1);

    }
};

2、找到数组第一个缺失的正整数。【1,3】缺失的是2.【4,5】缺失的是1.数组里应该是【1,2】

算法:构造一个等长度的数组,存放类似哈希表的数出现值

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        if(nums.size()==0)
            return 1;
        vector<int>save;
        save.resize(nums.size());
        //构造辅助数组,出现的数字是1,没出现的是0
        for (int i = 0; i < nums.size(); i++)
        {
            if(nums[i]>0 && nums[i] <=nums.size())
                save[nums[i]-1] = 1;
        }
        //在辅助数组里找空缺的数字
        for (int i = 0; i < save.size(); i++)
        {
            if(save[i] == 0)
                return i+1;
        }
        //如果数组里的数字是全的,那么缺失的是更大的数字
        return nums.size()+1;
    }
};

3、前缀和、前缀积的应用

前缀积的应用可以参考b[i]=a[0]a[1]…a[i-1]a[i+1]…的例题,使用先求出后缀积,再对应的乘上前缀积得出跳过a[i]的答案。

前缀和可以参考例题:把一个数组从中间任意位置P分开,使得前一半和与后一半和差值最小
算法:第一次遍历,得出前缀和
第二次对前缀和数组进行遍历,比较前一部分和总值减去前部分的差值进行差值比较。

class Solution {
public:
    int maxFrontSum(vector<int>& nums) {
        if(nums.size()<2)
            return 0;
        int tmp = 0;
        for (int i = 0; i < nums.size(); i++)
        {
            tmp += nums[i];
            nums[i] = tmp;
        }
        int sum = tmp;
        int maxvalue = -1;
        //记录分割点
        int res = -1;
        for (int i = 0; i < nums.size()-1; i++)
        {
            //当前前缀和
            int pre = nums[i];
            //其余后部分的和
            int behind = sum - pre;
            //差值
            int gap = abs(behind - pre );
            maxvalue = max(maxvalue,gap);
            //如果最大差值改变了,说明当前分割点可能是最大差值分割点
            if(maxvalue == gap)
                res = i;
        }
        //返回的数字是分割的前部分
        return res;
    }
};

通过前缀和的应用可以在O(N)的时间内找到分割点,所以对于涉及到和或者差的问题,想到前缀和与前缀差等概念。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值