【刷题(15】普通数组

一 普通数组基础

首先,我们根据下图先了解一下什么是前缀和。
在这里插入图片描述
既然我们明白了前缀和是怎么回事,那我们就来看一下我们该怎么输入
先给出答案,然后再给出分析。
答案:

for (int i = 1; i <= n; i ++ ){
	cin >> a[i];
	s[i] = s[i - 1] + a[i];
}
1
2
3
4

我们通过这副图来理解一下为什么这么写代码就可以得到前缀和
在这里插入图片描述
到现在,我们已经解决了输入问题和前缀和的问题,下面就是我们如何利用前缀和的时候了。
我们用前缀和有一个很大的优势,就是可以快速的得到某一个区间的区间总和

前缀和的优势:以(o1)的时间复杂度得到某块区间的总和
好,我们先来看一下怎么求一个区间的和
我们用 L 和 R 分别表示区间的左右端点,
那么
在这里插入图片描述
好,前缀的内容就这么多啦
下面奉上我的代码

#include <iostream>

using namespace std;

const int N = 100010;

int n, m;
int a[N], s[N];

int main(){
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) cin >> a[i], s[i] = s[i - 1] + a[i];
    
    while (m -- ){
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;
    }
    
    return 0;
    
}

何为前缀和算法?
前缀和算法,属于基础算法,一般来说没有固定的模板,但是其思路值得借鉴,我们来看一个案例就懂了
作用: 快速求一段和,一般暴力算法时间复杂度为O(n),而现在使用前缀和的时间复杂度可降为O(1)

具体实现:
求s[ l, r ]的区间和

for(int i = 1; i <= n; i++){
	s[i] = s[i-1] + a[i];
}
printf("%d",s[r] - s[l-1]);
1
2
3
4

值得注意的一点是,我们一般将S[0] = 0,原因如下:
假设我们需要计算S【1,10】,那么S10 - S0可以直接得出,Sr - S(l-1)

二 53. 最大子数组和

1 题目

在这里插入图片描述

2 解题思路

这道题要求的是最大子数组和。

对于子数组通常有两种处理方法:

前缀和;
滑动窗口
由于这道题是求和的,我们可以考虑使用前缀和来处理。

通过前缀和可以确定任意一个子数组的数组和。

在这里插入图片描述
可以看到,子数组[i,j)的和是通过两个前缀和相减得到的。那么如果我们固定被减数 preArr[j],那么只要减数最小,那么得到的子数组和就最大。

那么减数是什么?减数是 preArr[j] 之前出现过的前缀和。而最终得到的子数组是什么?是以 j 为右边界的和最大的子数组。

因此我们使用两个变量:

preSum: 累加当前位置的前缀和;
minPreSum: 记录当前位置之前的饿最小前缀和,初始为 0,表示子数组就是整个前缀。

图解算法过程

在这里插入图片描述

3 code

手写

在这里插入图片描述

c++

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result=INT_MIN;

        int preSum=0;
        int minPreSum=0;

        for(auto num:nums)
        {
            preSum+=num;

            //注意顺序
            result=max(result,preSum-minPreSum);
            minPreSum=min(minPreSum,preSum);

        }
        return result;

    }
};

python

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result=INT_MIN;

        int preSum=0;
        int minPreSum=0;

        for(auto num:nums)
        {
            preSum+=num;

            //注意顺序
            result=max(result,preSum-minPreSum);
            minPreSum=min(minPreSum,preSum);

        }
        return result;

    }
};

三 56. 合并区间

1 题目

在这里插入图片描述

2 解题思路

首先我们明确合并两个区间的过程是什么:
在这里插入图片描述
首先我们根据区间的起点做了一个排序,起点小的靠前,起点大的靠后;
其次我们根据前一个区间的终点和后一个区间的起点是否有重合,判断区间是否可以合并;
最后,合并后的区间起点一定是靠前的那个区间的起点,终点是两个区间中终点更大的那个;
从两个区间的合并过程中我们可以看出,合并区间:

根据区间起点排序;
维护一个当前合并的区间[start, end]
判断当前区间是否可以合并到当前的合并区间;可以则更新合并区间的终点,不可以这个区间作为新的一个合并区间去合并后面的区间。

在这里插入图片描述

3 code

手写

在这里插入图片描述

c++

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> result;

        sort(intervals.begin(),intervals.end());
        
        int left=intervals[0][0];
        int right=intervals[0][1];
        for(auto nums:intervals)
        {
            if(right>=nums[0])
            {//确定合并区间
                //防止[1 4] [2 3]情况出现
                right=max(nums[1],right);
            }
            else
            {//区间不连续,保存结果
                result.push_back({left,right});
                left=nums[0];
                right=nums[1];
            }
        }
        result.push_back({left,right});
        return result;
   
    }
};

python

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> result;

        sort(intervals.begin(),intervals.end());
        
        int left=intervals[0][0];
        int right=intervals[0][1];
        for(auto nums:intervals)
        {
            if(right>=nums[0])
            {//确定合并区间
                //防止[1 4] [2 3]情况出现
                right=max(nums[1],right);
            }
            else
            {//区间不连续,保存结果
                result.push_back({left,right});
                left=nums[0];
                right=nums[1];
            }
        }
        result.push_back({left,right});
        return result;
   
    }
};

四189. 轮转数组

1 题目

在这里插入图片描述

2 解题思路

(1)
在这里插入图片描述
(2)
在这里插入图片描述
(3)
在这里插入图片描述

3 code

手写

在这里插入图片描述

c++

class Solution {
public:
    void rotate(vector<int>& nums, int k) {

        k=k % nums.size();

        reverse(nums,0,nums.size()-1);
        reverse(nums,0,k-1);
        reverse(nums,k,nums.size()-1);
    }
private:
    void reverse(vector<int>& nums, int left, int right)
    {
        while(left<right)
        {
            int temp=nums[left];
            nums[left]=nums[right];
            nums[right]=temp;
            left++;
            right--;
        }
    }
}

;

python

class Solution {
public:
    void rotate(vector<int>& nums, int k) {

        k=k % nums.size();

        reverse(nums,0,nums.size()-1);
        reverse(nums,0,k-1);
        reverse(nums,k,nums.size()-1);
    }
private:
    void reverse(vector<int>& nums, int left, int right)
    {
        while(left<right)
        {
            int temp=nums[left];
            nums[left]=nums[right];
            nums[right]=temp;
            left++;
            right--;
        }
    }
};

五 238. 除自身以外数组的乘积

1 题目

在这里插入图片描述

2 解题思路

前缀积,后缀积
在这里插入图片描述

3 code

手写

在这里插入图片描述

c++

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        vector<int>result;
        int n=nums.size();
        //前缀积,后缀积
        int preDot[n];
        int postDot[n];
        preDot[0]=nums[0];
        postDot[n-1]=nums[n-1];
        for(int i=1;i<n;i++)
        {
            preDot[i]=nums[i]*preDot[i-1];
            postDot[n-i-1]=nums[n-i-1]*postDot[n-i];
        }

        
        result.push_back(postDot[1]);
        for(int i=1;i<nums.size()-1;i++)
        {
            result.push_back(preDot[i-1]*postDot[i+1]);
        }
        result.push_back(preDot[n-2]);

        return result;

    }
};

python

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        vector<int>result;
        int n=nums.size();
        //前缀积,后缀积
        int preDot[n];
        int postDot[n];
        preDot[0]=nums[0];
        postDot[n-1]=nums[n-1];
        for(int i=1;i<n;i++)
        {
            preDot[i]=nums[i]*preDot[i-1];
            postDot[n-i-1]=nums[n-i-1]*postDot[n-i];
        }

        
        result.push_back(postDot[1]);
        for(int i=1;i<nums.size()-1;i++)
        {
            result.push_back(preDot[i-1]*postDot[i+1]);
        }
        result.push_back(preDot[n-2]);

        return result;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BILLY BILLY

你的奖励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值