C++ 中将第 K 个元素减少到 0 的操作次数

2024年8月29日 | 阅读 8 分钟

引言

在各种算法和数据处理任务中,将某个索引处的元素通过几次操作减少到零是很常见的情况。这个问题经常出现在竞争性编程、数值分析以及许多其他计算算法中。在本文中,我们将探讨将数组的 Kth 元素减少到零的问题,并提供一个高效的 C++ 实现来执行此类任务。

问题陈述

给定一个整数数组和一个目标索引 K,问题是确定将数组的 Kth 元素减少到零所需的最小操作次数。每次操作都涉及从选定的元素中减去一个非负整数。此问题的核心目标是最小化执行这些操作后的数组总和,最终将 Kth 元素减少到零。

形式上,我们用大小为 N 的数组 A 来表示,其中 A[i] 是第 i 个元素。我们的目标是找出将 A[K] 变为零所需的条件。我们可以对任何选定的 A[i] 执行以下操作:

A[i] 中减去一个非负整数 x (0 ≤ x ≤ A[i])

总而言之,我们的目标是找到一个算法,该算法能够以最高效的方式解决问题,并以最少的计算量完成。

方法

有一个简单的解决方法

  • 首先,定义一个名为 operation 的变量,用于记录已执行的总操作次数。
  • 接下来,开始遍历数组,从第一个元素开始。
  • 计算当前元素 A[i](如果它是 Kth 元素)变为零所需的次数。
  • 更新到目前为止的总操作次数。
  • 最后,将总和作为结果返回。
  • 输入: N = 3, arr[] = {2, 3, 2}, K = 2
  • 输出 6

说明

  1. 应用第一次操作后,将 arr[0] 减一并将其推回,从而得到 {3, 2, 1} 作为更新后的 arr[]
  2. 应用第二次操作后,将 arr[0] 减一并将其推回,从而得到 {2, 1, 2} 作为更新后的 arr[]。
  3. 应用第三次操作后,将 arr[0] 减一并将其推回,从而得到 {1, 2, 1} 作为更新后的 arr[]。
  4. 应用第四次操作后,将 arr[0] 减一并将其从 arr[] 中移除。然后我们的新数组变为 {},而不是 {2, 1}。
  5. 应用第五次操作后,将 arr[0] 减一并将其推回,从而得到 {1, 1} 作为更新后的 array[]。
  6. 应用第六次操作后,arr[0] 被减一并从 arr[] 中移除,因此 arr[] 变为 {1}。
  7. 总共需要 6 次操作才能将 arr[2] 减少到 0。

程序(C++ 代码)

以下是上述方法的示例实现

输出

Minimum operations to reduce element at index 2 to zero: 2

说明

此实现是一种高效计算将数组 Kth 元素减少到零所需最小操作次数的方法。它的时间复杂度为 O(N),其中 N 是数组的大小。

1. 初始化

  • 为了计算总操作次数,我们初始化一个名为 "operations" 的变量,该变量将在我们对数组中的元素执行操作时递增。

2. 遍历数组

  • 从索引 0 开始,我们遍历数组中的每个元素,这样我们就可以逐个观察每个元素。

3. 识别 Kth 元素

  • 在此循环中,我们检查目标索引 k(应减少到零的 Kth 元素)是否与这些元素的当前索引匹配。
  • 之后,计算当当前索引等于 k 时,将此条目减少到零所需的操作次数。
  • 将此值添加到我们的变量 "operations" 中。它告诉我们处理 Kth 元素所需的操作次数,因为每次操作都涉及从手头的选定元素中减去一个非负整数。

4. 返回结果

  • 完成此循环中的所有迭代后,我们返回存储在 operations 变量中的总操作次数。

复杂度分析

时间复杂度

  • 我们的方法的 time complexity 是 O(N),其中 N 是数组的大小。
  • 我们遍历数组一次以计算所需操作的总次数。
  • 因此,由于我们只对数组中的每个元素执行固定数量的操作(主要是比较和加法),因此 time complexity 仍然与其大小成线性关系。

空间复杂度

  • 此方法的 space complexity 为 O(1),表示它需要 constant space。
  • 我们只需要使用几个变量(operations、i),它们负责保存当前状态和循环索引。
  • 无论输入数组有多大,算法仍然需要一定量的内存。
  • 因此,space complexity 不依赖于输入数组的大小。

程序 2:排序方法

让我们以另一个示例来说明使用 C++ 中的 排序方法 将 Kth 元素减少到 0 的操作数。

输出

Minimum operations to reduce element at index 2 to zero (Sorting Approach): 4

说明

1. 包含头文件

  • 此代码包含输入/输出 (iostream) 和 vector 操作 (vector, algorithm) 所必需的头文件。

2. 命名空间声明

  • 此代码使用 std 命名空间,允许直接访问标准库中定义的函数。

3. 函数 minOperationsToZeroSorting

  • 该函数接受 vector nums 表示整数数组,以及整数 k 表示要将每个其他元素归零的索引。
  • 之后,它使用 <algorithm> 头文件中的 sort 函数按非递减顺序对数组 nums 进行排序。
  • 它引入了一个名为 minElement 的变量,当数组排序后,该变量将获取数组中最小数字的值。
  • 这里发生的另一件重要事情是首先将 operations 设置为零,它将跟踪所做的每次操作。
  • 之后,它会一直遍历到索引 k(包含)的排序数组。
  • 在此步骤中,Kth 元素之前的每个元素都从最小元素 (minElement) 中减去,并添加到 operations 变量中。
  • 最后,将操作总数(存储在 operations 变量中)返回。

4. 主函数

  • 在 main() 函数中,定义了一个值为 {3, 5, 2, 8, 6} 的数组 nums。
  • 整数 k 等于 2,表示需要将此索引处的元素归零。
  • 将示例数组 nums 和 k 作为参数传递给 minOperationsToZeroSorting
  • 之后,使用排序方法,通过调用 minOperationsToZeroSorting(nums,k) 来找出并将所需的最少操作数(使索引 k 处的元素为零)打印到控制台,与上述步骤获得的结果一致。

程序 3:前缀和方法

让我们以另一个示例来说明使用 C++ 中的 前缀和方法 将 Kth 元素减少到 0 的操作数。

输出

Minimum operations to reduce element at index 2 to zero (Prefix Sum Approach): 10

说明

1. 头文件

  • 在此示例中,代码包含了输入/输出 (iostream) 和 vector 操作 (vector) 所必需的头文件。

2. 命名空间声明

  • 它利用 std 命名空间,允许直接访问标准库中定义的函数。

3. 函数 minOperationsToZeroPrefixSum

  • 此函数接受 vector nums(表示整数数组)和整数 k(表示要减少到零的元素的索引)。
  • 它初始化一个大小为 size() + 1 的 vector prefixSum,并将所有元素初始化为 0。此 vector 将存储数组的前缀和。
  • 之后,它会遍历每个元素(nums),从索引 1 的起始位置开始。
  • 最后,它通过将其当前元素添加到前一次迭代的前缀和中来计算其前缀和。
  • 在此循环结束后,返回 prefixSum[k+1],它表示到点 k 的总和。这个总和表示将 K 变为零所需的步数。

4. Main 函数

  • 在 main 函数中,示例数组 nums 被定义为具有值 {3, 5, 2, 8, 6}。
  • 整数 k 被定义为 2,表示此特定元素的索引应归零。
  • 之后,调用 minOperationsToZeroPrefixSum 函数,并传入示例数组 nums 和索引 k。
  • 结果将是使用前缀和方法将索引 k 处的元素最小化为零所需的最少操作数,然后将结果打印到控制台。

结论

在本文中,我们讨论了将数组的 Kth 元素减少到零的问题,并提供了一个高效的 C++ 实现来解决它。通过遵循给定的方法,我们可以有效地解决类似的问题,优化时间和空间复杂度。该算法在涉及数组操作的各种算法和计算场景中非常有用。