首页 > 编程语言 >【华为OD-E卷 - 最长连续子序列 100分(python、java、c++、js、c)】

【华为OD-E卷 - 最长连续子序列 100分(python、java、c++、js、c)】

时间:2025-01-19 15:01:01浏览次数:3  
标签:java 前缀 python sum OD 哈希 int 数组 长度

【华为OD-E卷 - 最长连续子序列 100分(python、java、c++、js、c)】

题目

有N个正整数组成的一个序列。给定整数sum,求长度最长的连续子序列,使他们的和等于sum,返回此子序列的长度,
如果没有满足要求的序列,返回-1

输入描述

  • 第一行输入是:N个正整数组成的一个序列

第二行输入是:给定整数sum

输出描述

  • 最长的连续子序列的长度

备注

  • 输入序列仅由数字和英文逗号构成,数字之间采用英文逗号分隔 序列长度:1 <= N <= 200 输入序列不考虑异常情况

用例

用例一:
输入:
1,2,3,4,2
6
输出:
3
用例二:
输入:
1,2,3,4,2
20
输出:
-1

python解法

  • 解题思路:
  • 本题目要求找出一个数组中,和为目标值 target 的最长子数组的长度。为了高效地解决问题,我们可以使用 前缀和(prefix sum)和 哈希表 来优化计算。

关键步骤:
前缀和:对于一个数组,前缀和是一个到当前位置为止的元素和,记录每一个元素到当前位置的和。通过前缀和的差值可以帮助我们找到和为目标值的子数组。
哈希表:使用哈希表 prefix_sum 来记录每个前缀和第一次出现的位置。若当前的前缀和减去目标值已经在哈希表中出现过,则表示从该位置到当前下标之间的子数组和为目标值。
步骤解析:
从头到尾遍历数组,维护一个累加的前缀和 current_sum。
对于每一个位置 i,计算 current_sum - target,如果它已经存在于 prefix_sum 哈希表中,说明从该位置到当前下标之间的子数组和等于目标值 target。
如果 current_sum 在哈希表中不存在,说明第一次遇到这个前缀和,将它与当前下标 i存入哈希表。
算法步骤:
初始化一个哈希表 prefix_sum,记录前缀和及其第一次出现的位置。我们假设前缀和为0的初始位置是 -1,这样便于处理从数组的开头就能达到目标值的情况。
遍历数组,计算每个位置的 current_sum。
如果 current_sum - target 存在于哈希表中,计算从该位置到当前下标的子数组长度,更新最大长度 max_len。
如果 current_sum 不在哈希表中,将其加入哈希表,记录当前下标。
时间复杂度:
时间复杂度为 O(n),其中 n 是数组的长度。遍历数组一次,每次查找和更新哈希表的操作都是 O(1)。

# 输入数组nums和目标值target
nums = list(map(int, input().split(",")))  # 输入的数组,按逗号分隔
target = int(input())  # 目标和

# 主函数,返回和为target的最长子数组长度
def findMaxLength():
    # 使用哈希表记录前缀和及其出现的位置,初始时前缀和为0对应的位置是-1
    prefix_sum = {0: -1}
    current_sum = 0  # 当前的前缀和
    max_len = -1  # 记录最长子数组的长度,初始化为-1表示还未找到

    # 遍历数组nums
    for i in range(len(nums)):
        # 更新当前的前缀和
        current_sum += nums[i]
        
        # 如果current_sum - target在哈希表中,表示存在一个子数组和为target
        if current_sum - target in prefix_sum:
            # 更新最大长度
            max_len = max(max_len, i - prefix_sum[current_sum - target])
        
        # 如果current_sum未出现过,记录它的位置
        if current_sum not in prefix_sum:
            prefix_sum[current_sum] = i

    return max_len  # 返回找到的最大子数组长度

# 输出结果
print(findMaxLength())

java解法

  • 解题思路
  • 本题要求在给定的数组中,找到和为 targetSum 的最长子数组的长度。该问题本质上是寻找一个和为给定值的连续子数组,并返回其最大长度。我们可以通过暴力法(两层循环)来解决这个问题。

关键思路:
暴力法:我们可以通过两层循环来遍历数组的所有子数组。在外层循环中,我们固定子数组的起始位置 start,在内层循环中遍历从 start 到数组末尾的所有可能的子数组结尾位置 end,计算每个子数组的和。

条件判断:如果某个子数组的和等于 targetSum,就更新最大长度 maxLength。

时间复杂度:这种方法的时间复杂度为 O(n²),其中 n 是数组的长度。因为我们对于每个可能的子数组,都要计算其和。

算法步骤:
输入处理:读取数组和目标值 targetSum。
解析输入:将输入的字符串分割并转换为整数数组。
暴力查找:通过两层循环,计算每个可能的子数组和,若等于目标值,更新最大长度。
返回结果:输出找到的最大长度

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 解析输入的数字序列
        int[] numbers = parseSequence(scanner.nextLine());
        // 读取目标和
        int sum = Integer.parseInt(scanner.nextLine());

        // 输出结果,调用findMaxSubarrayLength函数计算最大长度
        System.out.println(findMaxSubarrayLength(numbers, sum));
    }

    // 解析输入的数字序列,返回整数数组
    public static int[] parseSequence(String input) {
        String[] tokens = input.split(",");  // 以逗号为分隔符分割输入字符串
        int[] result = new int[tokens.length];  // 初始化整数数组
        for (int i = 0; i < tokens.length; i++) {
            result[i] = Integer.parseInt(tokens[i]);  // 将每个分割后的字符串转换为整数
        }
        return result;  // 返回解析后的数组
    }

    // 找到和为targetSum的最长子数组的长度
    public static int findMaxSubarrayLength(int[] numbers, int targetSum) {
        int maxLength = -1;  // 初始化最大长度,-1表示没有找到符合条件的子数组

        // 外层循环:遍历数组中的每个起始位置
        for (int start = 0; start < numbers.length; start++) {
            int currentSum = 0;  // 初始化当前子数组的和

            // 内层循环:遍历从start到数组末尾的每个结束位置
            for (int end = start; end < numbers.length; end++) {
                currentSum += numbers[end];  // 更新当前子数组的和

                // 如果当前子数组的和等于targetSum
                if (currentSum == targetSum) {
                    maxLength = Math.max(maxLength, end - start + 1);  // 更新最大子数组长度
                }
            }
        }

        return maxLength;  // 返回结果
    }
}

C++解法

  • 解题思路
更新中

C解法

  • 解题思路

  • 该题的目标是寻找给定整数数组中和为指定 targetSum 的最长子数组的长度。为了高效地解决这个问题,我们采用了滑动窗口(Sliding Window)技巧,通过维持一个动态调整的窗口,避免使用暴力法(两层循环)来提高效率。

关键思路:
滑动窗口:我们通过两个指针 left 和 right 来维持一个“窗口”,窗口内的元素之和小于等于 targetSum。每次扩展窗口(即增加 right 指针),当当前窗口的和大于 targetSum 时,我们通过移动 left 指针来缩小窗口,直到当前窗口的和不大于 targetSum。

动态更新窗口:每次找到符合条件的窗口时,检查该窗口的大小是否是目前找到的最大值,并更新最大长度。

时间复杂度:这个方法的时间复杂度是 O(n),其中 n 是数组的长度。通过滑动窗口技巧,left 和 right 每个指针最多只会遍历一次数组,因此时间复杂度为线性

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 解析输入的字符串,转换为整数数组,并返回数组的长度
int* parseInput(char* input, int* length) {
    char* token = strtok(input, ",");  // 使用strtok以逗号分隔字符串
    int* result = malloc(100 * sizeof(int));  // 分配一个较大的内存空间,假设最大输入为100个数
    int index = 0;

    // 遍历所有的token,将其转换为整数并存储到结果数组中
    while (token != NULL) {
        result[index++] = atoi(token);  // 使用atoi将字符串转换为整数
        token = strtok(NULL, ",");  // 获取下一个token
    }

    *length = index;  // 将数组的长度存入length中
    return result;  // 返回解析得到的整数数组
}

// 使用滑动窗口技术查找和为targetSum的最长子数组
int findLongestSubarray(int* nums, int length, int targetSum) {
    int maxLen = -1;  // 初始化最大长度为-1,表示如果没有找到子数组,则返回-1
    int currentSum = 0;  // 当前窗口的和
    int left = 0;  // 滑动窗口的左指针

    // 遍历数组,右指针从0到length-1
    for (int right = 0; right < length; right++) {
        currentSum += nums[right];  // 将当前元素加入到窗口中,更新当前和

        // 当当前窗口的和大于targetSum时,移动左指针缩小窗口
        while (currentSum > targetSum && left <= right) {
            currentSum -= nums[left++];  // 从窗口中移除左边的元素,并将左指针向右移动
        }

        // 如果当前窗口的和等于targetSum,更新最大长度
        if (currentSum == targetSum) {
            if (right - left + 1 > maxLen) {
                maxLen = right - left + 1;  // 更新最大子数组长度
            }
        }
    }

    return maxLen;  // 返回最大子数组长度
}

int main() {
    char input[100];  // 用于存储输入的字符串
    fgets(input, sizeof(input), stdin);  // 读取输入字符串
    input[strcspn(input, "\n")] = 0;  // 去除末尾的换行符

    int length;  // 数组的长度
    int* nums = parseInput(input, &length);  // 解析输入并返回整数数组

    int targetSum;  // 目标和
    scanf("%d", &targetSum);  // 读取目标和

    // 调用findLongestSubarray函数计算结果并打印
    printf("%d\n", findLongestSubarray(nums, length, targetSum));

    free(nums);  // 释放动态分配的内存
    return 0;
}

JS解法

  • 解题思路

  • 本题的目标是找到一个整数数组中,和为给定 target 的最长连续子数组,并返回其长度。我们可以使用 前缀和(Prefix Sum) 和 哈希表(Map) 技巧来高效地求解这个问题。

关键思路:
前缀和(Prefix Sum):
前缀和是指数组中某个位置之前(包括当前位置)的元素和。我们可以通过维护当前的前缀和来快速计算某一范围内的子数组的和。

哈希表(Map):
我们使用哈希表来记录每个前缀和首次出现的位置。具体地,假设当前索引为 i,当前前缀和为 prefixSum,我们希望找到一个之前的索引 j 使得 prefixSum - sum 出现在哈希表中,这样就能得到一个和为 sum 的子数组。子数组的长度就是 i - j。

具体步骤:

初始化一个哈希表 prefixSumMap,用来存储每个前缀和首次出现的索引,最初将 prefixSumMap[0] = -1,表示如果当前前缀和等于目标和 sum,从 0 到当前位置就是一个合法的子数组。
遍历数组,计算当前的前缀和 prefixSum,并检查 prefixSum - target 是否已经出现在哈希表中。如果出现,则说明找到了一个和为 target 的子数组,更新最大子数组长度 maxLen。
最终返回最长子数组的长度。
时间复杂度:
时间复杂度为 O(n),其中 n 是数组的长度。我们只遍历一次数组,并且每次操作哈希表的查询和更新都是常数时间 O(1)。
空间复杂度:
空间复杂度为 O(n),用于存储哈希表

async function main() {
    const input = await getInput();  // 获取用户输入
    const nums = input[0].split(",").map(Number);  // 将第一个输入转为整数数组
    const target = Number(input[1]);  // 第二个输入是目标和

    // 输出最长子数组的长度
    console.log(findLongestSubsequence(nums, target));
}

// 获取输入的函数,返回一个包含两个输入的数组
function getInput() {
    return new Promise((resolve) => {
        const rl = require('readline').createInterface({ input: process.stdin });
        const inputs = [];  // 用来保存输入的数组
        rl.on('line', (line) => inputs.push(line))  // 逐行读取输入
          .on('close', () => resolve(inputs));  // 输入完成后返回输入数组
    });
}

// 查找和为target的最长连续子数组
function findLongestSubsequence(nums, sum) {
    const prefixSumMap = new Map();  // 用哈希表记录前缀和和其对应的索引
    prefixSumMap.set(0, -1);  // 初始前缀和为0,对应的索引为-1
    let maxLen = -1;  // 存储最长子数组的长度
    let prefixSum = 0;  // 当前前缀和

    // 遍历数组
    for (let i = 0; i < nums.length; i++) {
        prefixSum += nums[i];  // 更新当前前缀和

        // 检查前缀和是否已经出现过,若出现过,说明存在一个和为target的子数组
        if (prefixSumMap.has(prefixSum - sum)) {
            // 更新最大子数组长度
            maxLen = Math.max(maxLen, i - prefixSumMap.get(prefixSum - sum));
        }

        // 如果当前前缀和没有出现过,记录当前前缀和的索引
        if (!prefixSumMap.has(prefixSum)) {
            prefixSumMap.set(prefixSum, i);
        }
    }

    return maxLen;  // 返回最长子数组的长度
}

main();  // 调用main函数,开始执行

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

标签:java,前缀,python,sum,OD,哈希,int,数组,长度
From: https://blog.csdn.net/CodeClimb/article/details/145065075

相关文章

  • 【华为OD-E卷 - 找出两个整数数组中同时出现的整数 100分(python、java、c++、js、c)】
    【华为OD-E卷-找出两个整数数组中同时出现的整数100分(python、java、c++、js、c)】题目现有两个整数数组,需要你找出两个数组中同时出现的整数,并按照如下要求输出:有同时出现的整数时,先按照同时出现次数(整数在两个数组中都出现并目出现次数较少的那个)进行归类,然后按照出......
  • 【华为OD-E卷 - 计算疫情扩散时间 100分(python、java、c++、js、c)】
    【华为OD-E卷-计算疫情扩散时间100分(python、java、c++、js、c)】题目在一个地图中(地图由n*n个区域组成),有部分区域被感染病菌。感染区域每天都会把周围(上下左右)的4个区域感染。请根据给定的地图计算,多少天以后,全部区域都会被感染。如果初始地图上所有区域全部都被感......
  • java 抽象类
    ​父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了(因为子类对象会调用自己重写的方法)。换句话说,父类可能知道子类应该有哪个功能,但是功能具体怎么实现父类是不清楚的(由子类自己决定),......
  • Python 项目和Pytorch 项目的环境构建
    python项目环境搭建首先下载软件包,打开安装创建项目:点击主菜单新建项目位置+pythonProject1构建python环境condecreate–p.envpython=3.10解释器:文件设置解释器本地解释器现有调试运行pytorch项目环境搭建先检查版本pip--version首先下载anaconda安装包这里......
  • leetcode11. 盛最多水的容器,双指针法
    leetcode11.盛最多水的容器给定一个长度为n的整数数组height。有n条垂线,第i条线的两个端点是(i,0)和(i,height[i])。找出其中的两条线,使得它们与x轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。示例1:输入:[1......
  • Java-抽象方法
    抽象方法:●抽象方法:将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。●抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类●抽象方法的定义格式:publicabstract返回值类型方......
  • java—接口
    接口:是一种规则,是对行为的抽象。接口的定义和使用接口用关键字interface来定义publicinterface接口名{}接口不能实例化接口和类之间是实现关系,通过implements关键字表示publicclass类名implements接口名{}接口的子类(实现类)要么重写接口中的所有抽象方法要么是抽......
  • leetcode——三数之和(java)
    给你一个整数数组nums,判断是否存在三元组[nums[i],nums[j],nums[k]]满足i!=j、i!=k且j!=k,同时还满足nums[i]+nums[j]+nums[k]==0。请你返回所有和为0且不重复的三元组。注意:答案中不可以包含重复的三元组。示例1:输入:nums=[-1,0,1,2,-1,-4]输......
  • Linux 上安装 Node.js
    在Linux上安装Node.js的方法取决于你使用的发行版。以下是常见的几种安装方法:方法1:通过包管理器安装(推荐)对于Ubuntu/Debian系统:更新系统包索引:sudoaptupdate安装Node.js(LTS版本)你可以直接使用Ubuntu/Debian的官方包管理器安装Node.js,但是推荐使用NodeS......
  • 前端必知必会-Node.js连接MongoDB 创建集合
    文章目录Node.js连接MongoDB创建集合创建集合总结Node.js连接MongoDB创建集合MongoDB中的集合与MySQL中的表相同创建集合要在MongoDB中创建集合,请使用createCollection()方法:示例获取您自己的Node.js服务器创建一个名为“customers”的集合:varMon......