Java前缀和算法题目练习

Java前缀和算法题目练习

前缀和

前缀和

在这里插入图片描述
题目解析:在一个数组中查询起对应区间的和,会查询多次
算法思想:暴力解法:每次查询都进行一次遍历,时间复杂度O(n*m)
前缀和解法:新定义一个数组,每一个下标存放的值是要查询数组的前下标对应值的和,这样我们在访问起某一个区间的时候,直接利用这个数组就非常快速
在这里插入图片描述


在这里插入图片描述
importjava.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息publicclassMain{publicstaticvoidmain(String[] args){Scanner in =newScanner(System.in);int n = in.nextInt();int m = in.nextInt();int[] arr =newint[n+1];//此时我们让其下标从1开始,这样可以省略边界问题考虑 arr[0]=0;for(int i =1;i <= n;i++){ arr[i]= in.nextInt();}//题目意思就是给了我们长度是n的数组,但是会有m查询//1.首先定义一个新的数组,其每一个下标对应的值是其从arr1开始到这个下标值的和long[] dp =newlong[n+1];for(int i =1;i <= n;i++){ dp[i]= dp[i -1]+ arr[i];}while(m >0){int l = in.nextInt();int r = in.nextInt();System.out.println(dp[r]- dp[l -1]); m--;}}}
时间复杂度:O(n + m)
空间复杂度:O(n)

二维前缀和

在这里插入图片描述
题目解析:和上一题一样,只不过这里变成了二维数组,要求的是对应子矩阵元素之和
前缀和:先定义一个新数组dp,其下标对应的值是原arr 数组[1,1] ~ [i, j]下标的和,此时还是让其下标从1开始这样就不用考虑下标越界情况
在这里插入图片描述


在这里插入图片描述
importjava.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息publicclassMain{publicstaticvoidmain(String[] args){Scanner in =newScanner(System.in);// 注意 hasNext 和 hasNextLine 的区别int n = in.nextInt();int m = in.nextInt();int q = in.nextInt();//下标从1开始int[][] arr =newint[n+1][m+1];for(int i =1;i <= n;i++){for(int j =1;j<=m;j++){ arr[i][j]= in.nextInt();}}//前缀和数组long[][] dp =newlong[n+1][m+1];for(int i =1;i<=n;i++){for(int j =1;j<=m;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();int y1 = in.nextInt();int x2 = in.nextInt();int y2 = in.nextInt();System.out.println(dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+ dp[x1-1][y1-1]); q--;}}}
时间复杂度:O(n*m + q)
空间复杂度:O(n * m)

寻找数组的中心下标

在这里插入图片描述
题目解析:找到一个下标,让其数组左边元素的和等于其右边元素的和
前缀和算法:由于暴力解法每次都要进行遍历多次,这样时间复杂度高
因此我们可以使用f和g两个数组,一个每一个下标用来放其前缀和,一个用来放后缀和,最后遍历一遍判断其f[i] == g[i]即可
在这里插入图片描述
classSolution{publicintpivotIndex(int[] nums){int n = nums.length;int[] f =newint[n];int[] g =newint[n];//此时f要从左向右填写,因为后一个要根据前一个填写for(int i =1;i < n;i++){ f[i]= f[i-1]+ nums[i-1];}for(int i = n-2;i >=0;i--){ g[i]= g[i+1]+ nums[i+1];}for(int i =0;i< n;i++){if(f[i]== g[i]){return i;}}return-1;}}
时间复杂度:O(n)
空间复杂度:O(n)

除自身以外数组的乘积

在这里插入图片描述
题目解析:返回一个answer数组,里面answer[i]表示的是nums数组中除了num[i]下标的值,其他所有元素的积,返回这个answer数组
前缀积:f表示前缀积,g表示后缀积

classSolution{publicint[]productExceptSelf(int[] nums){int n = nums.length;//一个前缀积和一个后缀积int[] f =newint[n];int[] g =newint[n];int[] ret =newint[n]; f[0]= g[n-1]=1;for(int i =1;i < n;i++){ f[i]= f[i-1]* nums[i-1];}for(int i = n -2;i >=0;i--){ g[i]= g[i+1]* nums[i+1];}for(int i =0; i<n;i++){ ret[i]= f[i]*g[i];}return ret;}}

和为k的子数组

在这里插入图片描述
题目解析:数组中找子数组和为k的个数
前缀和:有一个前缀和数组,这样每次我们只要在[ 0 , i-1]找出和为nums[i] - k即可,
但是如果sum[i] == k,此时就要从 [0,-1]中找0,因此可以先将<0,1>放入hash中
在这里插入图片描述
classSolution{publicintsubarraySum(int[] nums,int k){Map<Integer,Integer> hash =newHashMap<>(); hash.put(0,1);int sum =0;//表示前缀和int ret =0;for(int num : nums){ sum += num; ret += hash.getOrDefault(sum - k,0);//更新结果 hash.put(sum,hash.getOrDefault(sum,0)+1);//将其放入hash中}return ret;}}
时间复杂度:O(n)
空间复杂度:O(n)

和可被K整除的子数组

在这里插入图片描述
题目解析:在一个数组中找出所有子数组和可以整除k的子数组个数
这个题目和上一个求所有和为子数组的个数一样,一些细节处理方式都差不多,唯一不一样的是
在这里插入图片描述
在这里插入图片描述
classSolution{publicintsubarraysDivByK(int[] nums,int k){Map<Integer,Integer> hash =newHashMap<>();//刚开始要先将0%k放入进去,也就是<0,1>,防止当 hash.put(0% k,1);int sum =0;int ret =0;for(int num : nums){ sum += num;int r =(sum % k + k)%k; ret += hash.getOrDefault( r,0); hash.put(r,hash.getOrDefault(r,0)+1);}return ret;}}
时间复杂度:O(n)
空间复杂度:O(n)

连续数组

在这里插入图片描述
题目解析:找一个最长的子数组其和为0,并且此子数组区间中0和1的个数一样
题目转换,我们可以将其中的0看成-1,此时就变成了找出和为0的最长子数组,上面有一个题目是和为k的子数组,此时的k == 0
前缀和 + 哈希表
但是有很多细节不一样,
1.这里哈希表存放的是<前缀和,下标>
2.重复的哈希其不用存放,因为这里要求的是最长子数组
3.长度为i - j
4.<0,-1>,前缀和为0,存放的是-1
5.先使用,后存放入哈希表中
在这里插入图片描述
classSolution{publicintfindMaxLength(int[] nums){//此时可以将其0看成-1,此时就变成和为0的最长子数组的求解Map<Integer,Integer> hash =newHashMap<>();//当其[0,i]位置和为0时候,我们要从[0,-1]中找出和为0 hash.put(0,-1);int len =0;int sum =0;for(int i =0;i < nums.length ;i++){if(nums[i]==0){ sum -=1;}else{ sum +=1;}//从前面找和为sum,那后面和就为0,当然其j越靠前越好//因此如果已经有了和为sum,后面的就不用放进去了if(hash.containsKey(sum)){ len =Math.max(len,i - hash.get(sum));}else{//放入hash中 hash.put(sum,i);}}return len;}}
时间复杂度:O(n)
空间复杂度:O(n)

矩阵区域和

在这里插入图片描述
题目解析:给了一个二维数组,我们要返回一个相同的二维数组,每一个下标对应的值是其原本二维数组距离其为k的元素所围成的一个矩形中元素之和
前缀和矩阵,上面有一个题目是求(x1,y1) 到 (x2,y2)所围成矩阵的和就用到了前缀和矩阵
因此这里可以先求出前缀和数组,在使用的时候直接根据k求出其是那两个坐标 围成的矩形,有了坐标可以使用前缀和矩阵,这样就求出对应的值了
但是此时要注意其下标是不一样的,前缀和矩阵下标是从1开始
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
classSolution{publicint[][]matrixBlockSum(int[][] mat,int k){int m = mat.length;int n = mat[0].length;int[][] dp =newint[m+1][n+1];//构建前缀和其下标从1开始for(int i =1;i<= m;i++){for(int j =1;j<= n;j++){ dp[i][j]= dp[i-1][j]+ dp[i][j-1]- dp[i-1][j-1]+ mat[i-1][j-1];}}int[][] ret =newint[m][n];//使用的时候下标也要+1这样才能正常使用前缀和数组for(int i =0;i<m;i++){for(int j =0;j<n;j++){int x1 =Math.max(i-k,0)+1;int y1 =Math.max(j-k,0)+1;int x2 =Math.min(i+k, m -1)+1;int y2 =Math.min(j+k, n -1)+1; ret[i][j]= dp[x2][y2]- dp[x1-1][y2]- dp[x2][y1-1]+ dp[x1-1][y1-1];}}return ret;}}
时间复杂度:O(m * n)
空间复杂度:O(m * n)

Read more

Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 wasm_ffi 深入鸿蒙端侧硬核 WebAssembly 虚拟机沙盒穿透适配全景:通过异步极速 FFI 中继管道打通底层高算力异构服务并全面实现无损语言壁垒交互 前言 在 OpenHarmony 应用向高性能计算领域扩展的过程中,如何优雅地接入已有的 C/C++ 算法库(如加密引擎、重型图像处理、数学模拟)而又不失跨平台的便捷性?传统的 NAPI 虽然稳健,但在 Flutter 生态中,直接利用 WebAssembly (WASM) 配合 FFI(External Function Interface)的语义可以在一定程度上实现代码的高度复用。wasm_ffi 库为 Flutter 开发者提供了一套在 Dart 环境下调用 WASM

By Ne0inhk
三种适用于Web版IM(即时通讯)聊天信息的加密算法实现方案

三种适用于Web版IM(即时通讯)聊天信息的加密算法实现方案

文章目录 * **第一部分:引言与核心密码学概念** * **1.1 为什么IM需要端到端加密(E2EE)?** * **1.2 核心密码学概念与工具** * **第二部分:方案一:静态非对称加密(基础方案)** * **2.1 方案概述与流程** * **2.2 前端Vue实现(使用node-forge)** * **1. 安装依赖** * **2. 核心工具类 `crypto.js`** * **3. Vue组件中使用** * **2.3 后端Java实现(Spring Boot)** * **1. 实体类** * **2. Controller层** * **3. WebSocket配置** * **2.4 密钥管理、注册与登录集成** * **1. 用户注册/登录时生成密钥** * **2. 密钥设置页面** * **2.

By Ne0inhk
前端代码生成的大洗牌:当 GLM 4.7 与 MiniMax 挑战 Claude Opus,谁才是性价比之王?

前端代码生成的大洗牌:当 GLM 4.7 与 MiniMax 挑战 Claude Opus,谁才是性价比之王?

在 AI 辅助编程领域,长期以来似乎存在一条不成文的铁律:如果你想要最好的结果,就必须为最昂贵的模型买单(通常是 Anthropic 或 OpenAI 的旗舰模型)。然而,随着国产大模型如 GLM 4.7 和 MiniMax M2.1 的迭代,这一格局正在发生剧烈震荡。 最近,一场针对Claude Opus 4.5、Gemini 3 Pro、GLM 4.7 和 MiniMax M2.1 的前端 UI生成横向测评,打破了许多人的固有认知。在这场包含落地页、仪表盘、移动端应用等五个真实场景的较量中,不仅出现了令人咋舌的“滑铁卢”,更诞生了性价比极高的“新王”。 本文将深入拆解这场测试的细节,透过代码生成的表象,探讨大模型在工程化落地中的真实效能与成本逻辑。

By Ne0inhk
【Java Web学习 | 第14篇】JavaScript(8) -正则表达式

【Java Web学习 | 第14篇】JavaScript(8) -正则表达式

🌈个人主页: Hygge_Code🔥热门专栏:从0开始学习Java | Linux学习| 计算机网络💫个人格言: “既然选择了远方,便不顾风雨兼程” 文章目录 * JavaScript 正则表达式详解 * 什么是正则表达式🤔 * JavaScript 正则表达式的定义与使用🥝 * 1. 字面量语法 * 2. 常用匹配方法 * test() 方法🍋‍🟩 * exec() 方法🍋‍🟩 * 正则表达式的核心组成部分🐦‍🔥 * 1. 元字符 * 边界符 * 量词 * 字符类 * 2. 修饰符 * 简单示例🍂 JavaScript 正则表达式详解 正则表达式是处理字符串的强大工具,在 JavaScript 中被广泛应用于表单验证、文本处理和数据提取等场景。本文将从正则表达式的基本概念出发,详细介绍其语法规则和实际应用方法。 什么是正则表达式🤔 正则表达式是用于匹配字符串中字符组合的模式,在 JavaScript

By Ne0inhk