环形共享元素配对的最小翻转求解(需Numpy高效实现)
环形配对翻转最优解法
问题分析
给定环形结构的n个元素配对(第n个配对与第一个配对相邻),每个相邻配对存在公共元素。我们需要输出一个长度为n的0/1数组:
- 1:对应配对需翻转(交换两个元素位置)
- 0:无需翻转
目标是通过最少翻转次数,让所有相邻配对的公共元素彼此衔接(即前一个配对的尾元素等于后一个配对的头元素,首尾配对也需满足此规则)。
核心思路
由于是环形结构,第一个配对只有两种初始状态:不翻转或翻转。我们只需分别推导这两种状态下的完整翻转方案,再验证方案是否符合环形要求,最终选择翻转次数最少的可行方案。
具体步骤:
初始状态1:第一个配对不翻转
- 以第一个配对的尾元素作为初始衔接点
- 依次遍历后续每个配对:
- 若当前配对的头元素等于衔接点:无需翻转,更新衔接点为当前配对的尾元素
- 若当前配对的尾元素等于衔接点:需要翻转,更新衔接点为当前配对的头元素
- 最后检查最后一个配对的尾元素是否等于第一个配对的头元素(满足环形闭合)
初始状态2:第一个配对翻转
- 以第一个配对翻转后的尾元素(原头元素)作为初始衔接点
- 重复上述遍历逻辑
- 最后检查最后一个配对的尾元素是否等于第一个配对翻转后的头元素(原尾元素)
选择最优方案
收集所有可行方案,选择翻转次数最少的;若次数相同,任选其一
Numpy实现代码
import numpy as np def minimal_flips(pairs): arr = np.array(pairs) n = len(arr) if n == 0: return [] # 情况1:第一个配对不翻转 flip1 = np.zeros(n, dtype=int) prev_end = arr[0][1] valid1 = True for i in range(1, n): if arr[i][0] == prev_end: flip1[i] = 0 prev_end = arr[i][1] elif arr[i][1] == prev_end: flip1[i] = 1 prev_end = arr[i][0] else: valid1 = False break # 验证环形闭合 if prev_end != arr[0][0]: valid1 = False # 情况2:第一个配对翻转 flip2 = np.zeros(n, dtype=int) flip2[0] = 1 prev_end = arr[0][0] valid2 = True for i in range(1, n): if arr[i][0] == prev_end: flip2[i] = 0 prev_end = arr[i][1] elif arr[i][1] == prev_end: flip2[i] = 1 prev_end = arr[i][0] else: valid2 = False break # 验证环形闭合 if prev_end != arr[0][1]: valid2 = False # 筛选可行方案并选择最优 candidates = [] if valid1: candidates.append((flip1, np.sum(flip1))) if valid2: candidates.append((flip2, np.sum(flip2))) if not candidates: raise ValueError("输入不符合要求,未找到有效解") # 按翻转次数排序,选次数最少的 candidates.sort(key=lambda x: x[1]) return candidates[0][0].tolist() # 示例测试 if __name__ == "__main__": test_pairs = [(32,4),(4,1),(9,1),(9,16),(32,16)] print(minimal_flips(test_pairs)) # 输出: [0, 0, 1, 0, 1]
效率分析
- 时间复杂度:O(n),仅需两次线性遍历,Numpy的数组操作进一步提升了处理效率
- 空间复杂度:O(n),用于存储两种情况的翻转数组,属于最优空间复杂度
该解法利用环形结构的有限初始状态,避免了暴力枚举所有可能的翻转组合,确保了高效性,同时严格遵循题目要求实现最少翻转次数的目标。
内容的提问来源于stack exchange,提问作者user2373713
相关产品推荐
相关产品推荐

