2023-07-18:给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),

使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。

请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。

子数组 定义为原数组中连续的一组元素。

输入:nums = [3,1,4,2], p = 6。

输出:1。

答案2023-07-18:

大体过程如下:

1.计算整个数组的和对p取余,得到allMod

2.初始化一个空的映射m,并将映射中键为0,值为-1。该映射用于记录前缀和的某个余数最晚出现的位置。

3.初始化一个变量ans,表示最短子数组的长度,初值为无穷大。

4.初始化一个变量curMod,表示当前的前缀和余数,初值为0。

5.初始化一个变量find,表示要查找的余数,初值为0。

6.遍历数组nums中的每个元素:

  • 将当前元素加到curMod中,并对p取余,得到当前前缀和的余数curMod

  • 计算要查找的余数find = (curMod - allMod + p) % p

  • 在映射m中查找余数为find的键,如果存在则计算当前位置与查找到的位置之差,并更新ans为较小的值。

  • 更新映射m,将当前余数curMod存储到映射中。

7.如果ans没有被更新,则返回-1,否则返回ans

代码的时间复杂度为O(n),其中n是数组nums的长度。这是因为在遍历数组nums的过程中,需要进行常数时间的操作,包括计算前缀和的余数、更新映射m等。

代码的空间复杂度为O(n),其中n是数组nums的长度。这是因为需要使用一个映射m来记录前缀和的余数及其最晚出现的位置,映射m的大小不会超过数组的长度n。此外,还需要用几个额外的变量来存储一些中间结果,这些变量的空间占用也是常数级别的,不会随着输入规模n的增大而增加。

go完整代码如下:

package main

import (
"fmt"
) func minSubarray(nums []int, p int) int {
n := len(nums)
// 求出整体的余数
allMod := 0
for _, num := range nums {
allMod = (allMod + num) % p
}
if allMod == 0 {
return 0
}
// 记录前缀和的某个余数,最晚出现的位置
// 看课!然后看接下来的代码
m := make(map[int]int)
m[0] = -1
ans := 1<<31 - 1
curMod := 0
var find int
for i := 0; i < n; i++ {
// 0...i 累加和的余数
curMod = (curMod + nums[i]) % p
// 如果p = 7,整体余数2,当前余数5,那么找之前的部分余数是3
// 如果p = 7,整体余数2,当前余数1,那么找之前的部分余数是6
// 整体变成下面的公式,可以自己带入各种情况验证
find = (curMod - allMod + p) % p
val, ok := m[find]
if ok {
if i != n-1 || val != -1 {
// 防止删掉整体!
// ...i(n-1)
ans = min(ans, i-val)
}
}
m[curMod] = i
}
if ans == 1<<31-1 {
return -1
}
return ans
} func min(a, b int) int {
if a < b {
return a
}
return b
} func main() {
nums := []int{3, 1, 4, 2}
p := 6
result := minSubarray(nums, p)
fmt.Println(result)
}

rust代码如下:

use std::collections::HashMap;

fn min_subarray(nums: Vec<i32>, p: i32) -> i32 {
let n = nums.len(); // 求出整体的余数
let all_mod: i32 = nums.iter().sum::<i32>() % p;
if all_mod == 0 {
return 0;
} // 记录前缀和的某个余数,最晚出现的位置
let mut map: HashMap<i32, i32> = HashMap::new();
map.insert(0, -1); let mut ans = i32::max_value();
let mut cur_mod = 0;
let mut find; for i in 0..n {
// 0...i 累加和的余数
cur_mod = (cur_mod + nums[i]) % p; // 如果p = 7,整体余数2,当前余数5,那么找之前的部分余数是3
// 如果p = 7,整体余数2,当前余数1,那么找之前的部分余数是6
// 整体变成下面的公式,可以自己带入各种情况验证
find = (cur_mod - all_mod + p) % p; if map.contains_key(&find) {
if i != n - 1 || map[&find] != -1 {
// 防止删掉整体!
// ...i(n-1)
ans = ans.min(i as i32 - map[&find]);
}
} map.insert(cur_mod, i as i32);
} return if ans == i32::max_value() { -1 } else { ans };
} fn main() {
let nums = vec![3, 1, 4, 2];
let p = 6;
let result = min_subarray(nums, p);
println!("{}", result);
}

c++完整代码如下:

#include <iostream>
#include <vector>
#include <unordered_map> using namespace std; int minSubarray(vector<int>& nums, int p) {
int n = nums.size();
// 求出整体的余数
int allMod = 0;
for (int num : nums) {
allMod = (allMod + num) % p;
}
if (allMod == 0) {
return 0;
}
// 记录前缀和的某个余数,最晚出现的位置
// 看课!然后看接下来的代码
unordered_map<int, int> map;
map[0] = -1;
int ans = INT_MAX;
int curMod = 0, find;
for (int i = 0; i < n; i++) {
// 0...i 累加和的余数
curMod = (curMod + nums[i]) % p;
// 如果p = 7,整体余数2,当前余数5,那么找之前的部分余数是3
// 如果p = 7,整体余数2,当前余数1,那么找之前的部分余数是6
// 整体变成下面的公式,可以自己带入各种情况验证
find = (curMod - allMod + p) % p;
if (map.find(find) != map.end()) {
if (i != n - 1 || map[find] != -1) {
// 防止删掉整体!
// ...i(n-1)
ans = min(ans, i - map[find]);
}
}
map[curMod] = i;
}
return (ans == INT_MAX) ? -1 : ans;
} int main() {
vector<int> nums = { 3, 1, 4, 2 };
int p = 6;
int result = minSubarray(nums, p);
cout << "Result: " << result << endl;
return 0;
}

c完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h> int minSubarray(int* nums, int numsSize, int p) {
int n = numsSize;
// 求出整体的余数
int allMod = 0;
for (int i = 0; i < n; i++) {
allMod = (allMod + nums[i]) % p;
}
if (allMod == 0) {
return 0;
}
// 记录前缀和的某个余数,最晚出现的位置
// 看课!然后看接下来的代码
int* map = (int*)malloc(sizeof(int) * p);
for (int i = 0; i < p; i++) {
map[i] = -1;
}
map[0] = -1;
int ans = INT_MAX;
int curMod = 0, find;
for (int i = 0; i < n; i++) {
// 0...i 累加和的余数
curMod = (curMod + nums[i]) % p;
// 如果p = 7,整体余数2,当前余数5,那么找之前的部分余数是3
// 如果p = 7,整体余数2,当前余数1,那么找之前的部分余数是6
// 整体变成下面的公式,可以自己带入各种情况验证
find = (curMod - allMod + p) % p;
if (map[find] != -1) {
if (i != n - 1 || map[find] != -1) {
// 防止删掉整体!
// ...i(n-1)
ans = (ans < i - map[find]) ? ans : i - map[find];
}
}
map[curMod] = i;
}
free(map);
return (ans == INT_MAX) ? -1 : ans;
} int main() {
int nums[] = { 3, 1, 4, 2 };
int p = 6;
int numsSize = sizeof(nums) / sizeof(nums[0]);
int result = minSubarray(nums, numsSize, p);
printf("Result: %d\n", result);
return 0;
}

2023-07-18:给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空), 使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果的更多相关文章

  1. 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。

    /** * 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标. * * 你可以假设每种输入只会对应一个答案.但是,数组中 ...

  2. 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。

    谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数. Google2009华南地 ...

  3. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

  4. 最接近的三数之和(给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数, 使得它们的和与 target 最接近。返回这三个数的和)

    例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 思路:首先对数组进行排序     ...

  5. 给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。-----力扣

    给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积. 示例: 输入: [1 ...

  6. 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表

    这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...

  7. 从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行。请采用循环控制语句来实现。

    Scanner sc=new Scanner(System.in); System.out.println("请输入一个正整数:"); int ss=sc.nextInt(); i ...

  8. 17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行。请采用循环控制语句来实现。 (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和。) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1

    17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行.请采用循环控制语句来实现. (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和.) 1 1 1 1 ...

  9. 在排序数组中查找元素的第一个和最后一个位置(给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。)

    示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例 2: 输入: nums = [5,7,7,8,8,10], target = 6 输出 ...

  10. 刷题3:给定一个数组 nums,判断 nums 中是否存在三个下标 a,b,c数相加等于targe且a,b,c不相等

    题目: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,下标 ,a ,b , c 对应数相加等于 targe 找出所有满足条件且不重复的三元组下标 解析: ...

随机推荐

  1. Go语言实现基于HTTP的内存缓存服务

    所有的缓存数据都存储在服务器的内存中,因此重启服务器会导致数据丢失,基于HTTP通信会将使开发变得简单,但性能不会太好 缓存服务接口 本程序采用REST接口,支持设置(Set).获取(Get)和删除( ...

  2. Java运行准备JDR JRE JVM知识和环境变量的作用

    JDK.JRE.JVM简介 JDK:Java Development Kit   Java开发者工具包 JRE:Java runtime environment Java运行环境 JVM:Java V ...

  3. Java关键字以及标识符

    Java中有许多关键字,关键字是什么意思呢? 我用自己的分析来表达一下吧. Java就是源自于生活的,我们都有自己的名字.所以它也会有许多的名字,每个名字都有各自不同的特性(作用),都是系统定义好的. ...

  4. dotnet初探:用miniapi创建一个自己的url

    致谢 首先写在前面,非常感谢微软mvp桂素伟先生的技术分享,因为微软的文档大部分都如机器翻译般的生硬,让人难以读下去,正是他的无私分享为我的.net学习旅程提供了方向,非常感谢.如果大家对他比较感兴趣 ...

  5. cesium源码编译调试及调用全过程

    完整记录一次cesium源码从下载.打包.调用.调试的全过程. 本文使用软件或API版本: VSCode Node:12.18.3 cesium版本:1.94 总体步骤: 下载源码 执行npm ins ...

  6. Awesome GPT 来了!

    大家好!我是韩老师. GPT, ChatGPT, OpenAI, LLM(大语言模型)等等技术的出现与应用,改变了许多的行业和人. 长期来看,类 GPT 的技术会对整个世界有着持续的改变. 我们几乎每 ...

  7. 【Python基础】推导式(列表、字典、集合)

    推导式是一种简洁.高效的语法,用于从一个可迭代对象中生成新的可迭代(iterable)对象. 通常情况下,在以下情况可以考虑使用推导式: 只需要简单的表达式来计算新的可迭代对象的元素. 可迭代对象不是 ...

  8. ad-hoc实战

    ad-hoc实战 要求:利用Ansible搭建一个简易的作业网站,web端文件上传目录共享至nfs端,nfs的数据同步至backup 环境准备 主机名 主机角色 外网IP 内网IP m01 ansib ...

  9. Vue使用:style动态给css中某样式赋值

    template中 <span class="successOrError" :style="{'--fontColor':"green"}&q ...

  10. 项目打包后配置到node服务器

    1.将项目进行打包 npm run build项目根目录下会多出一个打包好的由.js .html .css文件组成的dist文件夹,如图 2.搭建node微型服务器   新建文件夹命名"no ...