做游戏网站赚钱么云服务器怎么用详细步骤
Problem: 2197. 替换数组中的非互质数
文章目录
- 整体思路
- 完整代码
- 时空复杂度
- 时间复杂度:O(N * log U)
- 空间复杂度:O(N)
整体思路
这段代码旨在解决一个数组变换问题:给定一个整数数组 nums,需要不断地合并相邻的、不互质(最大公约数 > 1)的两个数,直到数组中任意相邻的两个数都互质为止。合并规则是将这两个数替换为它们的最小公倍数 (LCM)。
该算法巧妙地利用了 栈 (Stack) 的思想来模拟这个合并过程。虽然代码中使用的是 ArrayList,但其 add(入栈)、getLast(窥视栈顶)、removeLast(出栈)等操作完全符合栈的“后进先出” (LIFO) 特性。
-
核心思想:栈式处理
- 算法将最终的结果数组看作一个栈
st。它从左到右遍历输入的nums数组,逐个处理每个数x。 - 当处理一个新数
x时,它需要与栈顶的元素进行比较。如果它们不互质,就需要合并。合并后的新数可能会继续与新的栈顶元素不互质,所以这个合并过程需要持续进行,直到新数与栈顶元素互质,或者栈为空。
- 算法将最终的结果数组看作一个栈
-
算法步骤:
- 初始化一个空的列表(作为栈)
st。 - 遍历
nums数组中的每一个元素x。 - 对于每个
x,进入一个while循环:
a. 检查条件:!st.isEmpty() && gcd(x, st.getLast()) > 1。这个条件判断栈是否为空,以及当前数x是否与栈顶元素st.getLast()不互质。
b. 合并操作:如果条件满足,说明需要合并。
*int y = st.removeLast();:将栈顶元素y弹出。
*x = (x / gcd(x, y) * y);:计算x和y的最小公倍数 (LCM),并将结果赋给x。这里使用了lcm(x, y) = (|x * y|) / gcd(x, y)的公式,为了防止溢出,写成了(x / gcd(x, y)) * y的形式。
c. 循环继续:合并后得到的新x,需要继续与新的栈顶元素进行比较,因此while循环会继续执行,直到x与栈顶互质或栈为空。 - 入栈:当
while循环结束后,说明当前的x(可能是原始的x,也可能是多次合并后的结果)已经可以安全地放在栈顶了。执行st.add(x),将其压入栈中。
- 初始化一个空的列表(作为栈)
-
gcd辅助函数- 算法依赖于一个
gcd函数来计算两个数的最大公约数 (Greatest Common Divisor)。 - 代码中实现的是经典的欧几里得算法(辗转相除法),这是一个非常高效的计算最大公约数的方法。
- 算法依赖于一个
-
返回结果
- 当
nums数组中的所有元素都处理完毕后,栈st中剩下的元素就是最终的结果序列,将其返回。
- 当
完整代码
import java.util.ArrayList;
import java.util.List;class Solution {/*** 合并数组中所有不互质的相邻元素,直到任意相邻元素都互质。* @param nums 输入的整数数组* st.add(x);}return st;}/*** 使用欧几里得算法(辗转相除法)计算两个整数的最大公约数 (GCD)。* @param x 第一个整数* @param y 第二个整数* @return x 和 y 的最大公约数*/private int gcd(int x, int y) {// 循环直到余数为 0while (y != 0) {int temp = y;y = x % y; // 新的 y 是 x 除以 y 的余数x = temp; // 新的 x 是原来的 y}// 当 y 为 0 时,x 就是最大公约数return x;}
}
时空复杂度
- 设
N是nums数组的长度。 - 设
U是nums数组中元素的最大值。
时间复杂度:O(N * log U)
- 外层循环:
for (int x : nums)遍历nums数组一次,执行N次。 - 内层
while循环:- 这个循环的行为是“合并”式的。每次循环都会消耗掉栈顶的一个元素。
- 在整个算法的生命周期中,一个元素最多被压入栈一次,也最多被弹出一次。
- 因此,
while循环的总执行次数(在所有外层循环中累加)不会超过N次。
gcd函数:- 欧几里得算法的复杂度与输入数值的对数成正比。计算
gcd(x, y)的时间复杂度大约是 O(log(min(x, y)))。 - 在我们的算法中,每次调用
gcd,其参数都与输入中的数值或它们的LCM相关。我们可以用U(输入最大值) 作为其复杂度的上界,即 O(log U)。
- 欧几里得算法的复杂度与输入数值的对数成正比。计算
综合分析:
总的时间复杂度大致是 (外层循环和内层循环的总迭代次数) * (单次 gcd 的时间)。
由于总迭代次数是 O(N) 级别,每次迭代都可能调用 gcd,所以总的时间复杂度是 O(N * log U)。
空间复杂度:O(N)
- 主要存储开销:算法使用了一个列表
st来作为栈。 - 空间大小:
- 在最坏的情况下,如果
nums数组中的所有元素都两两互质,那么st栈将会存储所有N个元素。 - 因此,
st占用的空间与输入规模N成线性关系。
- 在最坏的情况下,如果
gcd函数:gcd函数是迭代实现的,只使用了常数个额外变量,空间复杂度是 O(1)。
综合分析:
算法所需的额外空间主要由栈 st 决定。因此,其空间复杂度为 O(N)。
