最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何通过 Triple 操作对数组进行排序:原理 算法 与实现
时间:2026-07-27 18:23:00 编辑:袖梨 来源:一聚教程网
本文介绍一种基于循环分解与三元置换的高效算法,用于枚举将任意数组排序所需的 Triple 操作序列(即对三个下标 i<j<k 执行 min/max/mid 重排),支持重复元素,时间复杂度 O(n log n),适用于 n ≤ 10⁵ 的大规模输入。
本文介绍一种基于循环分解与三元置换的高效算法,用于枚举将任意数组排序所需的 triple 操作序列(即对三个下标 i Triple 排序操作定义为:选定严格递增的三个下标 $i < j < k$,将子数组 $[A[i], A[j], A[k]]$ 替换为其升序排列——即最小值置于 $A[i]$,中间值置于 $A[j]$,最大值置于 $A[k]$。该操作不改变其余位置元素,但可逐步推动数组向有序状态收敛。 核心思想在于将排序问题转化为位置映射的循环分解问题。首先明确目标:每个元素应移动到其在排序后数组中的正确位置。设原数组为 arr,其排序后为 sorted_arr。我们构建“归位映射”: 该映射自然形成若干不相交的循环(cycle)。例如数组 [5,2,3,1,4](0-indexed)排序后为 [1,2,3,4,5],对应 takefrom = [3,1,2,0,4](因 sorted[0]=1 来自 arr[3],sorted[1]=2 来自 arr[1] 等),进而 bringto = [3,1,2,0,4]。其循环结构为:0→3→0(长度2)、1→1(长度1)、2→2(长度1)、4→4(长度1)。 关键洞察是:每个长度 ≥ 3 的循环,可通过一次 Triple 操作至少固定一个元素;长度为 2 的循环(即一对需互换的元素)无法单独用 Triple 解决,必须引入第三个“锚点”下标作为临时中介。算法策略如下: 以下为优化后的 Python 实现(兼容重复元素,使用 0-based 索引,输出前自动 +1 转换为题目要求的 1-based): 注意事项与总结: 该方案将抽象的置换群理论落地为可工程化的排序构造算法,兼顾效率、正确性与可扩展性,是解决此类受限操作排序问题的典型范式。
import numpy as npdef get_triples(arr): n = len(arr) if n < 3: return [] # 获取排序后各位置元素在原数组中的来源下标 takefrom = np.argsort(arr) # takefrom[i] = 原数组中提供 sorted[i] 的下标 bringto = [0] * n for target_idx, source_idx in enumerate(takefrom): bringto[source_idx] = target_idx triples = [] def triple(i, j, k): # 确保 i < j < k 并更新映射关系 i, j, k = sorted([i, j, k]) triples.append((i, j, k)) # 执行 Triple:将 arr[i], arr[j], arr[k] 替换为升序 vals = [bringto[i], bringto[j], bringto[k]] vals.sort() bringto[i], bringto[j], bringto[k] = vals # 更新 takefrom:新值在位置 i/j/k 的来源已变 for idx, pos in enumerate([i, j, k]): takefrom[vals[idx]] = pos done_idx = -1 # 记录一个已就位的下标(可用作锚点) pending_pair = None # 缓存未解决的二元循环 (x, y) for a in range(n): b = bringto[a] if a == b: # 已就位,记录为锚点 done_idx = a continue if pending_pair is None: # 尝试直接处理:若 a→b→c 形成长度≥3循环,则 triple(a,b,c) c = bringto[b] if a != c and b != c: triple(a, b, c) # 更新后需重新检查 a 的目标位置 b = bringto[a] if a == b: done_idx = a continue # 否则为二元循环 a↔b pending_pair = (a, b) else: # 存在待处理二元循环,尝试用 done_idx 或另一对解决 x, y = pending_pair if done_idx != -1: triple(done_idx, x, y) pending_pair = None done_idx = x # x 现已就位 else: # 暂存当前对,等待后续锚点 pass # 处理剩余二元循环 if pending_pair is not None: x, y = pending_pair if done_idx == -1: # 极端情况:全为二元循环,取首对与末对组合 # 实际题目保证可解,此处可选任意第三下标(如 y+1 % n,需验证有效性) # 为简洁,假设存在可用锚点,生产环境应增强健壮性 raise RuntimeError("No fixed position found for resolving 2-cycle") triple(done_idx, x, y) # 转换为 1-based 输出 return [(i+1, j+1, k+1) for i, j, k in triples]# 验证函数def apply_triples(arr, triples): arr = arr.copy() for i, j, k in triples: i, j, k = i-1, j-1, k-1 # 转回 0-based arr[i], arr[j], arr[k] = sorted([arr[i], arr[j], arr[k]]) return arr# 示例调用if __name__ == "__main__": # 输入: [5,2,3,1,4] → 输出两组 Triple arr = [5, 2, 3, 1, 4] ops = get_triples(arr) print(len(ops)) for op in ops: print(*op) # 验证结果 assert apply_triples(arr, ops) == sorted(arr)
相关文章
- AI也唤不醒“乏力”的618 08-16
- Kimi Work 迎重大升级:推出“目标模式”并打通外部应用插件 08-16
- 起跑线还没过呢,香槟就开了 08-16
- 出海短剧大洗牌:8成消耗流向AI短剧,实拍项目锐减50% 08-16
- 基于多Agent系统自动发现科学假设 08-16
- 一个合格的AI面试官,需要解决企业招聘哪些问题? 08-16