小C的逆序对挑战

31 阅读3分钟

def solution(n: int, x: int, y: int, a: list) -> int: # 检查是否已经有逆序对 has_inversion = False for i in range(n - 1): if a[i] > a[i + 1]: return 0 # 已经有逆序对 # 如果所有元素相同,至少需要1次操作 if len(set(a)) == 1: return 1 # 检查可以通过减少或增加元素得到逆序对 min_operations = float('inf') # 对于每一对相邻元素 a[i] 和 a[i+1] for i in range(n - 1): if a[i] < a[i + 1]: # 选取操作来制造逆序对 # 1. 减少 a[i + 1] reduce_cost = (a[i + 1] - a[i]) // y + 1 # 2. 增加 a[i] increase_cost = (a[i + 1] - a[i] + x - 1) // x
min_operations = min(min_operations, min(reduce_cost, increase_cost)) return min_operations if name == 'main': print(solution(3, 1, 2, [1, 3, 5]) == 2) print(solution(4, 5, 7, [4, 6, 10, 9]) == 0) print(solution(5, 3, 2, [7, 7, 7, 7, 7]) == 1) 代码分析 函数定义: solution(n: int, x: int, y: int, a: list) -> int:接受四个参数,分别是数组长度 n、增加操作的步长 x、减少操作的步长 y 和数组 a。 检查是否已经有逆序对: 遍历数组 a,如果发现相邻的两个元素 a[i] 和 a[i + 1] 满足 a[i] > a[i + 1],则说明数组中已经有逆序对,直接返回 0。 检查所有元素是否相同: 使用 set(a) 来获取数组 a 的所有唯一元素,如果 len(set(a)) == 1,说明所有元素相同,至少需要 1 次操作来打破这个顺序,返回 1。 计算最小操作次数: 初始化 min_operations 为无穷大。 遍历数组 a 中的相邻元素 a[i] 和 a[i + 1],如果 a[i] < a[i + 1],则计算使 a[i] 和 a[i + 1] 形成逆序对所需的最小操作次数。 reduce_cost:通过减少 a[i + 1] 的值来形成逆序对,计算需要的操作次数。 increase_cost:通过增加 a[i] 的值来形成逆序对,计算需要的操作次数。 更新 min_operations 为 reduce_cost 和 increase_cost 中的较小值。 返回结果: 返回计算得到的最小操作次数 min_operations。 思路分析 预处理: 首先检查数组 a 是否已经包含逆序对,如果包含则无需任何操作,直接返回 0。 检查数组 a 是否所有元素相同,如果相同则至少需要 1 次操作来打破顺序。 计算最小操作次数: 遍历数组 a 中的相邻元素对,只关注那些满足 a[i] < a[i + 1] 的元素对,因为它们是唯一可能通过操作形成逆序对的元素对。 对于每一对这样的元素,分别计算通过减少 a[i + 1] 或增加 a[i] 来形成逆序对所需的操作次数。 使用整除运算符 // 来计算操作次数,因为每次操作有一定的步长(x 或 y),所以必须向上取整(通过加 1 实现)。 复杂度分析: 遍历数组两次,时间复杂度为 O(n),其中 n 是数组 a 的长度。 空间复杂度为 O(1),因为除了输入参数和几个变量外,没有使用额外的空间。 边界条件: 考虑了数组已经包含逆序对的情况。 考虑了所有元素相同的情况。 通过整除和取余操作,正确处理了步长和操作次数的计算。