华为OD-E卷-01 补种未成活胡杨100分(python、java、c++、js、c)

题目描述

近些年来,我国防沙治沙取得显著成果。某沙漠新种植N棵胡杨(编号1-N),排成一排。
一个月后,有M棵胡杨未能成活。
现可补种胡杨K棵,请问如何补种(只能补种,不能新种),可以得到最多的连续胡杨树?

输入描述:

  • N 总种植数量,1 <= N <= 100000

  • M 未成活胡杨数量,M 个空格分隔的数,按编号从小到大排列,1 <= M <= N

  • K 最多可以补种的数量,0 <= K <= M

输出描述:

  • 最多的连续胡杨棵树

用例1

输入

5
2
2 4
1

输出

3

说明 补种到2或4结果一样,最多的连续胡杨棵树都是3。

用例2

输入

10
3
2 4 7
1

输出

6

说明 补种第7棵树,最多连续胡杨树棵数位6(5,6,7,8,9,10)

python思路:

  • 解题思路:

  • 初始化树木状态: 我们首先将树木的状态表示为一个长度为 n 的数组 trees,其中 1 表示树木存活,0 表示树木已经死亡。输入的
    dead_indices 数组给出了死亡树木的位置(是 1-based 的,需要转化成 0-based)。

    滑动窗口: 我们使用两个指针 left 和 right 来表示当前考虑的连续区间。right 指针从左到右遍历整个数组,left
    指针表示当前区间的左边界。我们维护一个 zeros_count 来记录当前窗口内死树的数量。

    窗口调整: 每当窗口中的死树数量超过了 k,我们就移动 left 指针来缩小窗口,直到死树的数量不超过
    k。每次更新窗口时,我们记录当前窗口的长度,并更新最大长度 max_length。

    返回结果: 遍历完整个数组后,max_length 就是我们能找到的最大长度的连续区域。

  • 关键点:

  • 滑动窗口算法: 本算法通过维护一个动态变化的窗口,能够在 O(n) 时间复杂度内找到最长的符合条件的区间。 边界条件处理:
    在处理 dead_indices 时,注意数组是 1-based,而 Python 数组是 0-based,所以我们需要进行转换。

  • 时间复杂度分析:

    时间复杂度: 由于每个元素最多被 left 或 right 指针遍历一次,因此时间复杂度是 O(n),其中 n
    是树木的数量。 空间复杂度: 我们使用了一个长度为 n 的数组来表示树木状态,因此空间复杂度是 O(n)。

python解法:

def max_continuous_trees(n, m, dead_indices, k):
    # 将死树的索引转化为集合,以便快速查找
    dead_set = set(dead_indices)
    
    # 初始化树木数组,默认所有树木都是活的(1表示活树)
    trees = [1] * n
    # 将死树位置置为0
    for index in dead_indices:
        trees[index - 1] = 0  # dead_indices是1-based,所以我们要减去1使其变为0-based

    max_length = 0  # 记录最大连续区域的长度
    left = 0  # 左指针
    zeros_count = 0  # 记录当前窗口内的死树数量

    # 遍历整个数组,right是右指针
    for right in range(n):
        if trees[right] == 0:  # 如果当前树木是死树
            zeros_count += 1  # 死树数量加1

        # 如果当前窗口内的死树数量超过了k,调整左指针
        while zeros_count > k:
            if trees[left] == 0:  # 如果左边界是死树
                zeros_count -= 1  # 死树数量减1
            left += 1  # 移动左指针,缩小窗口

        # 更新最大连续区域长度
        max_length = max(max_length, right - left + 1)

    return max_length  # 返回最大连续区间的长度


if __name__ == "__main__":
    # 读取输入数据
    n = int(input())  # 树木总数
    m = int(input())  # 死树的数量
    dead_indices = list(map(int, input().split()))  # 死树的位置列表
    k = int(input())  # 允许的最大死树数量

    # 计算结果并输出
    result = max_continuous_trees(n, m, dead_indices, k)
    print(result)

java解法:

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 创建Scanner对象用于输入
        Scanner sc = new Scanner(System.in);

        // 输入数组的大小
        int size = sc.nextInt();
        // 输入最多允许的零的个数
        int toRemove = sc.nextInt();

        // 创建并初始化数组,所有元素初始为1
        int[] arr = new int[size];
        Arrays.fill(arr, 1);

        // 输入并设置数组中要置为零的索引位置
        for (int i = 0; i < toRemove; i++) {
            int index = sc.nextInt() - 1;  // 输入的索引是从1开始,减去1转为0基索引
            arr[index] = 0;  // 将该索引位置的元素置为零
        }

        // 输入最多允许的零的个数
        int maxZeros = sc.nextInt();
        
        // 调用findMaxSubarray函数计算结果并输出
        System.out.println(findMaxSubarray(arr, maxZeros));
    }

    // findMaxSubarray方法用于找到符合条件的最长子数组
    public static int findMaxSubarray(int[] arr, int maxZeros) {
        // 左指针,初始化为0
        int left = 0;
        // 当前窗口中零的个数
        int zeroCount = 0;
        // 最大子数组的长度
        int maxLength = 0;

        // 右指针,遍历数组
        for (int right = 0; right < arr.length; right++) {
            // 如果当前元素为零,零的数量增加
            if (arr[right] == 0) {
                zeroCount++;
            }

            // 当零的个数超过maxZeros时,收缩窗口
            while (zeroCount > maxZeros) {
                // 如果左边的元素是零,减少零的数量
                if (arr[left] == 0) {
                    zeroCount--;
                }
                // 移动左指针,缩小窗口
                left++;
            }

            // 更新最大子数组的长度
            maxLength = Math.max(maxLength, right - left + 1);
        }

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

c++解法:

#include 
#include 
#include 

#define MAX_TREES 10000  // 最大树木数量的定义

// 函数findMaxContinuous,用于找到最长的连续子数组,该子数组中最多有maxPlant个死树(即值为0的元素)
int findMaxContinuous(int trees[], int totalTrees, int maxPlant) {
    int start = 0;  // 左指针,表示子数组的起始位置
    int deadIndices[MAX_TREES];  // 存储死树(值为0)的位置
    int deadCount = 0;  // 当前窗口中死树的个数
    int maxLength = 0;  // 最长子数组的长度

    // 右指针,遍历整个树木数组
    for (int end = 0; end < totalTrees; end++) {
        if (trees[end] == 0) {  // 如果当前树是死的(值为0)
            deadIndices[deadCount++] = end;  // 将当前死树的位置加入deadIndices数组

            // 如果当前窗口中的死树数量超过了maxPlant,更新窗口
            if (deadCount > maxPlant) {
                // 计算并更新当前最长子数组的长度
                maxLength = (end - start > maxLength) ? end - start : maxLength;

                // 将左指针移到第一个死树的后面,即start跳到deadIndices[0] + 1的位置
                start = deadIndices[0] + 1;

                // 将deadIndices数组中的死树位置往前移动,移除掉最早的死树
                for (int i = 1; i < deadCount; i++) {
                    deadIndices[i - 1] = deadIndices[i];
                }
                // 减少死树计数
                deadCount--;
            }
        }

        // 更新当前窗口的最大长度
        maxLength = (end - start + 1 > maxLength) ? end - start + 1 : maxLength;
    }

    // 返回最终找到的最长合法子数组的长度
    return maxLength;
}

int main() {
    int totalTrees, deadTrees, maxPlant;
    
    // 输入树木的总数和死树的数量
    scanf("%d %d", &totalTrees, &deadTrees);

    // 初始化一个数组treeLine,表示所有树初始为活树(值为1)
    int treeLine[MAX_TREES];
    for (int i = 0; i < totalTrees; i++) {
        treeLine[i] = 1;  // 所有树初始值为1,表示活树
    }

    // 输入死树的索引,并将对应位置的树标记为死树(值为0)
    for (int i = 0; i < deadTrees; i++) {
        int deadIndex;
        scanf("%d", &deadIndex);
        treeLine[deadIndex - 1] = 0;  // 将该位置的树设为死树
    }

    // 输入最大允许的死树数量
    scanf("%d", &maxPlant);

    // 调用findMaxContinuous函数并输出结果
    printf("%d\n", findMaxContinuous(treeLine, totalTrees, maxPlant));

    return 0;
}

js解法:

// 引入 readline 模块,用于从标准输入获取用户输入
const readline = require("readline");

// 创建一个 readline 接口,用于处理输入和输出
const rl = readline.createInterface({
    input: process.stdin,  // 标准输入
    output: process.stdout,  // 标准输出
});

// 用于存储输入的各行数据
const inputs = [];

// 监听输入的每一行数据
rl.on("line", (input) => {
    // 将每行输入保存到 inputs 数组中
    inputs.push(input);

    // 当输入的行数达到4行时,表示输入已完成
    if (inputs.length === 4) {
        // 解析输入数据
        const total = parseInt(inputs[0], 10);  // 树的总数
        const deadCount = parseInt(inputs[1], 10);  // 死树的数量
        const deadPositions = inputs[2].split(" ").map(Number);  // 死树的位置数组
        const maxReplant = parseInt(inputs[3], 10);  // 最大可重新种植的死树数

        // 调用 findMaxConsecutive 函数来计算结果
        const result = findMaxConsecutive(total, deadPositions, maxReplant);
        
        // 输出计算结果
        console.log(result);

        // 清空 inputs 数组,准备处理下一个输入(如果有的话)
        inputs.length = 0;
    }
});

// 函数 findMaxConsecutive 用于寻找最长的连续子数组,子数组中最多可以有 k 个死树
function findMaxConsecutive(n, deadTrees, k) {
    let leftPtr = 0;  // 左指针,表示窗口的起始位置
    let replantCnt = 0;  // 当前窗口内的死树数量
    let maxConsec = 0;  // 最大的合法子数组长度
    let deadPos = new Set(deadTrees);  // 使用 Set 存储死树的位置,便于快速查找

    // 遍历数组,使用 rightPtr 作为右指针,表示当前窗口的结束位置
    for (let rightPtr = 0; rightPtr < n; rightPtr++) {
        // 如果当前右指针指向的树是死树,增加死树计数
        if (deadPos.has(rightPtr + 1)) {
            replantCnt++;
        }

        // 如果当前窗口内的死树数量超过了允许的最大数量 k,移动左指针收缩窗口
        while (replantCnt > k) {
            // 如果左指针指向的是死树,减少死树计数
            if (deadPos.has(leftPtr + 1)) {
                replantCnt--;
            }
            // 移动左指针,缩小窗口
            leftPtr++;
        }

        // 更新最大子数组的长度
        maxConsec = Math.max(maxConsec, rightPtr - leftPtr + 1);
    }

    // 返回最大连续合法子数组的长度
    return maxConsec;
}

c解法:

#include 
#include 
#include 

#define MAX_TREES 10000  // 定义树木数组的最大长度

// 函数 findMaxContinuous 用于找出最多可以允许 maxPlant 个死树的最长连续子数组
int findMaxContinuous(int trees[], int totalTrees, int maxPlant) {
    int start = 0;  // 初始化左指针,表示窗口的起始位置
    int deadIndices[MAX_TREES];  // 用于存储当前窗口中死树的位置
    int deadCount = 0;  // 当前窗口内死树的数量
    int maxLength = 0;  // 存储最大子数组的长度

    // 遍历整个树木数组,右指针右移
    for (int end = 0; end < totalTrees; end++) {
        // 如果当前树是死树(值为0),将其索引记录在 deadIndices 数组中
        if (trees[end] == 0) {
            deadIndices[deadCount++] = end;  // 增加死树计数并记录该死树的位置

            // 如果当前窗口中的死树数量超过了 maxPlant,缩小窗口
            if (deadCount > maxPlant) {
                // 计算并更新当前最大合法子数组的长度
                maxLength = (end - start > maxLength) ? end - start : maxLength;

                // 将左指针移动到第一个死树的后面,即 start 移动到 deadIndices[0] + 1
                start = deadIndices[0] + 1;

                // 将 deadIndices 数组中已经处理过的死树位置移除,更新剩余死树的位置
                for (int i = 1; i < deadCount; i++) {
                    deadIndices[i - 1] = deadIndices[i];
                }
                // 死树数量减少
                deadCount--;
            }
        }

        // 每次右指针移动时,更新最大子数组的长度
        maxLength = (end - start + 1 > maxLength) ? end - start + 1 : maxLength;
    }

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

int main() {
    int totalTrees, deadTrees, maxPlant;

    // 读取输入的总树木数量和死树的数量
    scanf("%d %d", &totalTrees, &deadTrees);

    // 初始化树木数组,所有树初始为活树(1)
    int treeLine[MAX_TREES];
    for (int i = 0; i < totalTrees; i++) {
        treeLine[i] = 1;  // 默认值为 1,表示活树
    }

    // 读取死树的索引,并将相应位置的树标记为死树(0)
    for (int i = 0; i < deadTrees; i++) {
        int deadIndex;
        scanf("%d", &deadIndex);
        treeLine[deadIndex - 1] = 0;  // 注意输入的索引是从1开始,需要减1
    }

    // 读取最大允许的死树数量
    scanf("%d", &maxPlant);

    // 调用 findMaxContinuous 函数来计算最大合法子数组的长度,并输出结果
    printf("%d\n", findMaxContinuous(treeLine, totalTrees, maxPlant));

    return 0;
}

代码已自测,如您发现有未覆盖到的情况,欢迎私信或留言! 会在看到的第一时间优化,感谢_

你可能感兴趣的:(算法题,华为od,(A+B+C+D+E,卷)收录分享,java,华为od,python,c++,算法)