整型数组索引与值互换实现置换逆运算方法
今天要聊聊一个看似基础但极易出错的编程操作:如何将表示置换关系的整型数组“翻转”过来,也就是构建它的逆置换。这在密码学中的轮转器实现(例如恩尼格玛仿真)里非常常见——编码和解码本质上就是一对对称的置换运算。
先理清核心概念。假设有一个数组 arr,其中 arr[i] = j 表示索引 i 映射到值 j。现在我们希望构造一个新数组 inv,使得 inv[j] = i,即交换索引与值的角色。这个操作常被称为“数组索引与值互换”或“置换求逆”,是双射函数求逆的直观体现:已知 f(i) = arr[i],求 f⁻¹(j) = i。

举个具体的例子。假设正向映射为 [4, 0, 3, 1, 2],即输入 0 得到输出 4,输入 1 得到输出 0,依此类推。那么它的逆置换应变成 [1, 3, 4, 2, 0]——意思是,输出 0 来自输入 1,输出 1 来自输入 3,依此类推。这实际上就是数学上的双射函数求逆:已知 f(i) = arr[i],求 f⁻¹(j) = i。
但在动手编码之前,必须先认清一个极易踩坑的核心问题。
最大的风险在于:绝不能原地修改,否则遍历过程中原始数据会被覆盖,导致逻辑彻底崩溃。
常见错误是直接在原数组上赋值,比如写 R1.Pattern[origPatt[i]] = i,却没有提前保存原始状态。问题在于 origPatt = R1.Pattern 只是复制了引用,而非数据本身。后续对 R1.Pattern 的写入会实时覆盖尚未读取到的原始值——等到循环进行到后面时,引用的已是改写过的东西,结果自然全乱套了。
正确的做法其实很简单:
- 先创建一个独立副本,用
.clone()或者手动新建数组都可以; - 然后用原数组的值作为新数组的索引,用原数组的索引作为新数组的值;
- 最关键的是,确保原数组的内容在整个循环过程中始终不变。
下面是最安全、最清晰的 Java 实现:
int[] original = {4, 0, 3, 1, 2}; // 正向置换:f(0)=4, f(1)=0, f(2)=3, f(3)=1, f(4)=2
int[] inverse = new int[original.length];
// 构造逆置换:令 inverse[original[i]] = i
for (int i = 0; i < original.length; i++) {
inverse[original[i]] = i;
}
// 输出结果:[1, 3, 4, 2, 0]
System.out.println(Arrays.toString(inverse)); // [1, 3, 4, 2, 0]
需要留意几个关键细节:
- 数组必须是有效的置换:
original必须包含从 0 到 n−1 的每个整数恰好一次,不能有重复或越界,否则original[i]作为索引时会抛出ArrayIndexOutOfBoundsException。 - 禁止原地计算:千万不要在
original上直接赋值,必须使用独立的目标数组。 - 如果确实需要就地更新(例如覆盖原来的轮子配置),那就先做一次深拷贝:
int[] origCopy = R1.Pattern.clone();,然后基于origCopy构建逆置换,最后写回R1.Pattern。 - 该算法的时间复杂度为 O(n),空间复杂度为 O(n),已是理论最优解,没有更快的方案。
总结起来其实就一句话:交换索引与值的本质,就是构造置换的数学逆元。牢记“以值为新索引、以原索引为新值”,同时严格分离读写内存区域,就能稳稳支撑起密码学仿真这类对确定性映射有严苛要求的场景。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
列表遍历时动态判断阈值并返回相应文本
遍历数值列表时,先筛选满足阈值的元素,再根据结果输出列表或友好提示。推荐使用列表推导式结合条件判断,注意边界用`>=`,空列表自动为假。也可用`any()`提前终止遍历,提升效率。此法简洁,避免显式循环,特别适合阈值筛选。
Maven项目中如何强制使用本地构建的依赖版本
多模块开发中强制使用本地依赖的正确做法是使用-SNAPSHOT版本并配合`-U`参数强制更新,或重构为多模块项目统一管理生命周期。避免使用版本范围语法或手动复制JAR,确保构建行为可靠可重复。
Go语言net.Conn并发写安全与原子性保障解析
Go标准库中net Conn支持并发方法调用,但Write()不保证原子性。多goroutine同时写入时,系统可能拆分数据包,导致内容交错,破坏消息边界。必须使用互斥锁或bufio Writer等显式同步机制确保写操作完整性,不可依赖系统调用本身的原子性。
Python在Windows系统中获取指定卷标U盘驱动器字母的方法
使用Pythonwmi库通过Win32_Volume接口查询Windows系统中卷标为“TOSHIBA”的U盘盘符。需安装wmi和pywin32,注意大小写区分及多设备过滤。仅适用于Windows。
TP6.0消息已读功能基于Redis Bitmap未读计数方案
TP6 0中使用Redis位图实现消息已读标记,每条消息仅占一个比特,内存效率高。需将消息ID映射为连续偏移量,通过SETBIT和GETBIT操作。需提前维护用户ID到偏移量的映射表,注意键过期与驱动类型(phpredis与predis)问题。此方法内存极省,适合海量消息场景,且需确保偏移量唯一。
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-08 06:50
2026-07-08 06:50
2026-07-08 06:50
2026-07-08 06:49
2026-07-08 06:49
2026-07-08 06:49
2026-07-08 06:49
2026-07-08 06:49
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

