#P3097. 补种未成活的胡杨(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 240
            Accepted: 61
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>双指针          
 
补种未成活的胡杨(100分)
题目描述
近些年来,我国防沙治沙取得显著成果。某沙漠新种植 N 棵胡杨(编号 1-N),排成一排。
一个月后,有 M 棵胡杨未能成活。
现可补种胡杨 K 棵,请问如何补种(只能补种,不能新种),可以得到最多的连续胡杨树?
输入描述
- N:总种植数量,1 ≤ N ≤ 100000
 - M:未成活胡杨数量,M 个空格分隔的数,按编号从小到大排列,1 ≤ M ≤ N
 - K:最多可以补种的数量,0 ≤ K ≤ M
 
输出描述
输出最多的连续胡杨树棵数。
样例
输入1:
5
2
2 4
1
输出1:
3
输入2:
10
3
2 4 7
1
输出2:
6
题解思路
问题分析
这个问题可以转换为一个滑动窗口问题,我们要找到一段连续的胡杨树的区间,最多包含 K 棵可以补种的死树,并且这段区间的长度最大。
- 我们可以通过一个布尔数组记录每棵树是否死亡。这样,滑动窗口可以快速判断当前窗口内死树的数量。
 - 使用双指针(滑动窗口)的技术,维护一个左指针和右指针的区间,在右指针逐步右移的同时,如果窗口内的死树数量超过了 K,那么就将左指针向右移动,直到死树数量不超过 K。
 
算法步骤
- 
初始化:
- 用一个布尔数组 
vis来标记每棵树是否死亡。True表示存活,False表示死亡。 - 初始化两个指针 
left和right,分别指向窗口的左右边界,max_len用于记录最大的连续存活树数,dead_count用于记录当前窗口内死亡树的数量。 
 - 用一个布尔数组 
 - 
遍历树的位置:
- 对于每个右指针的位置 
right,判断该位置的树是否死亡,如果死亡则dead_count加 1。 - 如果窗口内死亡树的数量大于 K,则左指针逐步右移,直到死亡树数量小于等于 K。
 - 每次计算当前窗口的长度,更新 
max_len。 
 - 对于每个右指针的位置 
 - 
结束:
- 当遍历完成后,
max_len即为最多连续存活的树的数量。 
 - 当遍历完成后,
 
时间复杂度
- 初始化 
vis数组的时间复杂度为 O(N)。 - 遍历所有树的过程中,滑动窗口的操作复杂度为 O(N),因此总的时间复杂度为 O(N)。
 
代码实现
Python 实现
def max_consecutive_trees(N, M, dead_trees, K):
    # 创建一个布尔数组,标记每棵树是否死亡
    vis = [True] * (N + 1)
    
    # 将死树标记为 False
    for tree in dead_trees:
        vis[tree] = False
    
    left = 0  # 滑动窗口的左边界
    max_len = 0  # 存储最大连续树的长度
    dead_count = 0  # 当前窗口内死树的数量
    
    # 遍历每一棵树的位置
    for right in range(1, N + 1):
        # 如果当前树死亡,增加死树数量
        if not vis[right]:
            dead_count += 1
        
        # 如果死树数量超过 K,左指针右移,直到死树数量不超过 K
        while dead_count > K:
            if not vis[left + 1]:
                dead_count -= 1
            left += 1
        
        # 更新最大连续树的长度
        max_len = max(max_len, right - left)
    
    return max_len
# 输入读取部分
N = int(input())  # 总树的数量
M = int(input())  # 死树的数量
dead_trees = [int(x) for x in input().split()]  # 死树的位置
K = int(input())  # 最多可以补种的死树数量
# 调用函数并输出结果
print(max_consecutive_trees(N, M, dead_trees, K))
Java 实现
import java.util.*;
public class Main {
    public static int maxConsecutiveTrees(int N, int M, int[] deadTrees, int K) {
        boolean[] vis = new boolean[N + 1];  // 创建一个布尔数组标记每棵树是否死亡
        Arrays.fill(vis, true);  // 默认所有树都存活
        for (int tree : deadTrees) {
            vis[tree] = false;  // 死树标记为 false
        }
        int left = 0, maxLen = 0, deadCount = 0;
        for (int right = 1; right <= N; right++) {
            // 如果当前树死亡,增加死树数量
            if (!vis[right]) {
                deadCount++;
            }
            // 如果死树数量超过 K,左指针右移,直到死树数量不超过 K
            while (deadCount > K) {
                if (!vis[left + 1]) {
                    deadCount--;
                }
                left++;
            }
            // 更新最大连续树的长度
            maxLen = Math.max(maxLen, right - left);
        }
        return maxLen;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();  // 总树的数量
        int M = sc.nextInt();  // 死树的数量
        int[] deadTrees = new int[M];
        for (int i = 0; i < M; i++) {
            deadTrees[i] = sc.nextInt();
        }
        int K = sc.nextInt();  // 最多可以补种的死树数量
        // 调用函数并输出结果
        System.out.println(maxConsecutiveTrees(N, M, deadTrees, K));
    }
}
C++ 实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int maxConsecutiveTrees(int N, int M, vector<int>& deadTrees, int K) {
    vector<bool> vis(N + 1, true);  // 创建一个布尔数组标记每棵树是否死亡
    for (int tree : deadTrees) {
        vis[tree] = false;  // 死树标记为 false
    }
    int left = 0, maxLen = 0, deadCount = 0;
    for (int right = 1; right <= N; right++) {
        // 如果当前树死亡,增加死树数量
        if (!vis[right]) {
            deadCount++;
        }
        // 如果死树数量超过 K,左指针右移,直到死树数量不超过 K
        while (deadCount > K) {
            if (!vis[left + 1]) {
                deadCount--;
            }
            left++;
        }
        // 更新最大连续树的长度
        maxLen = max(maxLen, right - left);
    }
    return maxLen;
}
int main() {
    int N, M, K;
    cin >> N >> M;
    vector<int> deadTrees(M);
    for (int i = 0; i < M; i++) {
        cin >> deadTrees[i];
    }
    cin >> K;
    // 调用函数并输出结果
    cout << maxConsecutiveTrees(N, M, deadTrees, K) << endl;
    return 0;
}
        题目描述
近些年来,我国防沙治沙取得显著成果。某沙漠新种植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)