当前位置: 首页 > news >正文

前缀和代码解析

前缀和是指数组一定范围的数的总和,常见的有两种,一维和二维,我会用两道题来分别解析

一维

DP34 【模板】前缀和

题目:

题目解析:

暴力解法

直接遍历数组,遍历到下标为 l 时,开始进行相加,直到遍历到下标为 r ,最后返回总和.这样做的时间复杂度为: O(n)

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        //接收数据
        int n = in.nextInt(),q=in.nextInt();
        int[] arr = new int[n+1];
        arr[0]=0;
        for(int i=1;i<=n;i++){
            arr[i]=in.nextInt();
        }
        while(q>0){
            int l=in.nextInt(),r=in.nextInt();
            int sum = 0;
            for(int i =l;i<=r;i++){
                sum+=arr[i];
            }
            System.out.println(sum);
            q--;
        }
    }
}

虽然代码本身是没有问题的,但是在某些情况下会运行超时

优化

对于前缀和来说,我们可以使用动态规划的部分知识来进行解决,总共分为两步

1.预处理前缀和数组

我们创建一个新的数组,数组的规模和原数组保持一致,如图:

 

但是在我们求dp数组时,难免会对原数组重复计算,这样会增加代码的耗时,有没有简洁的方法呢?

当然是有的,从dp的获得式中我们可以发现, dp[i] = dp[i-1]+arr[i] 

2.使用数组

最后我们就可以返回值, 也就是上文提到的 dp[r]-dp[l-1] 

代码

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    // 注意 hasNext 和 hasNextLine 的区别
    //接收数据
    int n = in.nextInt(),q=in.nextInt();
    int[] arr = new int[n+1];
    arr[0] = 0;
    for(int i=1;i<arr.length;i++){
        arr[i] = in.nextInt();
    }
    //计算动态数组
    long[] dp = new long[n+1];
    dp[0] = 0;
    for(int i=1;i<dp.length;i++){
        dp[i]=dp[i-1]+arr[i];
    }
    //处理结果
    while(q>0){
        int l=in.nextInt(),r=in.nextInt();
        System.out.println(dp[r]-dp[l-1]);
        q--;
    }
}

在代码中我们可以看到,我们为数组增加了辅助节点,也就是 arr[0] 和 dp[0] ,那么为什么要增加这个辅助节点呢?或者为什么在使用数组的时候,下标要从1开始计算呢?

因为如果我们没有辅助节点或者从0开始计算,那么当 l (求前缀和的起点) 为 0 时,那么 dp[l-1] 就会越界

运行结果

二维

二维数组也就是矩阵,在计算矩阵的前缀和时,我们需要更注意一些细节

例题: DP35 【模板】二维前缀和

这道题大致与上一道题相似,所以就不进行暴力解法了,直接开始解析

也就是说,这里我们已经得到了用于动态规划的数组 dp ,我们只要再将dp中的值进行计算,就可以得到最后的值了

所以,最后要得出的答案就是 D = dp[x2][y2] -dp[x1-1][y1] -dp[x1][y1-1] +dp[x1-1][y1-1] 

代码:

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    // 注意 hasNext 和 hasNextLine 的区别
    //获取数据
    int n = in.nextInt(),m=in.nextInt(),q=in.nextInt();
    int[][] arr = new int[n+1][m+1];
    for(int i=1;i<n+1;i++){
        for(int j=1;j<m+1;j++){
            arr[i][j] = in.nextInt();
        }
    }

    //设置动态矩阵
    long[][] dp = new long[n+1][m+1];
    for(int i=1;i<n+1;i++){
        for(int j=1;j<m+1;j++){
            dp[i][j] = dp[i-1][j]+dp[i][j-1]+arr[i][j]-dp[i-1][j-1];
        }
    }
    //得出答案
    while(q>0){
        int x1=in.nextInt(),y1=in.nextInt(),x2=in.nextInt(),y2=in.nextInt();
        System.out.println(dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]);
        q--;
    }
}

 运行结果:

相关文章:

  • Docker基础-常见命令
  • 库制作与原理
  • 《Python实战进阶》专栏 No 5:GraphQL vs RESTful API 对比与实现
  • 电路笔记(PCB):使用kicad进行滤波器的瞬态分析(时间响应分析)仿真
  • 03_pyqt5 + vlc 实现视频播放器
  • Deepseek-ClickHouse数据库的安全策略
  • 浪漫壁纸的元素构成及创作方向
  • linux usb 驱动 - configfs 文件系统
  • DistilQwen2.5发布:通义千问蒸馏小模型再升级
  • Grafana使用日志4--直接对接Zabbix数据库的一些注意点
  • DeepSeek-R1技术全解析:如何以十分之一成本实现OpenAI级性能?
  • FFmpeg.NET:.NET 平台上的音视频处理利器
  • PDF转HTML 超级好用 免费在线转换PDF 完美转换格式
  • [特殊字符]《封印adb的黑暗通道:让系统文件成为魔法禁书区的终极指南》[特殊字符]
  • DeepSeek 部署实战:Ollama + 多客户端 + RAG
  • 【数三角——枚举,哈希】
  • OceanBase + DeepSeek:5分钟免费搭建企业知识库
  • K8s部署主从结构MySQL服务
  • C++的三种对象模型
  • 项目访问使用 docker bridge 网络模式(端口映射)配置详解
  • 保定网站制作哪家好建设/2021年热门关键词
  • 做pc端网站必知/郑州网络推广大包
  • 网站建设报价单/常见的网络推广方法有哪些
  • 设计必备网站/现在外贸推广做哪个平台
  • 猎聘做简历的网站收费靠谱吗/seo前景
  • 网页设计图片怎么放进去/seo双标题软件