给定数组
[a1 a2 a3 ... an b1 b2 b3 ... bn c1 c2 c3 ...cn]
不使用额外的内存如何重新排序成数组
[a1 b1 c1 a2 b2 c2 a3 b3 c3 ... an bn cn]
答案 0 :(得分:11)
您的问题也可以改为“如何进行就地矩阵换位?”。要了解原因,请假设在两个数组中的每个子序列之后添加换行符。这会将第一个数组转换为NxM矩阵,将第二个数组转换为MxN矩阵。
尽管如此,非方形矩阵并非易事。有关问题及其解决方案的详细说明,请参阅the Wikipedia page on In-place matrix transposition。
答案 1 :(得分:6)
假设您的意思是O(1)内存(或取决于模型O(log n))而不是没有额外的内存,则存在线性时间就地算法。
本文:http://arxiv.org/abs/0805.1598有一个算法,当你有
时 a1 ... an b1 ... bn
并希望转换为
b1 a1 b2 a2 ... bn an
。
本文还提到你可以将其推广到其他k-way shuffle。在你的情况下,k = 3。
本文中的算法将给出以下内容:
从a1 a2 ... an b1 b2 ... bn c1 c2 ... cn
开始并转换为
c1 b1 a1 c2 b2 a2 ... cn bn an
另一个传递,你可以轻松获得a1 b1 c2 a2 b2 c2 ... an bn cn
。
现在为了概括本文中的算法,我们需要选择素数p,这样k就是p ^ 2的原始根。
对于k = 3,p = 5将会这样做。
现在要应用算法,首先需要找到最大的m< n这样的3m + 1是5的幂。
注意:这只会在3m + 1是偶数 5的幂时发生。因此,当你试图找到m时,你实际上可以使用25的幂。 (5 ^奇数 - 1不能被3整除。)
找到m后,
你将数组洗牌为
[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]
然后使用循环方法(参考论文)获取前3m元素,使用5的幂(包括1 = 5 ^ 0)作为不同循环的起点)并进行尾递归其余的。
现在转换
a1 a2 ... an b1 b2 ... bn c1 c2 ... cn
到
[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]
首先进行循环转换
a1 a2 ... am [b1 b2 bm a(m+1) .. an] b(m+1) .. bn c1 c2 ... cn
(方括号中的元素是移位的元素)
然后进行循环移位以获得
a1 a2 ... am b1 b2 bm a(m+1) .. an [c1 c2 ..cm b(m+1) .. bn ] c(m+1) ... cn
然后最后转移到
a1 a2 ... am b1 b2 bm [c1 c2 ..cm a(m+1) .. an ] b(m+1) .. bn c(m+1) ... cn
请注意,循环移位可以在O(n)时间和O(1)空间中完成。
因此整个算法是O(n)时间和O(1)空间。
答案 2 :(得分:2)
您可以根据索引计算每个项目的目标位置。
groupSize = N/3
group = i/groupSize
rank = i - group * groupSize
dest = rank * 3 + group
您可以将此计算与循环排序一起使用,以便在线性时间内将每个元素放置在适当的位置。唯一的问题是跟踪哪些项目已经到位。你需要的只是N位。对于某些类型的数据,您可以从数据项本身“窃取”一些。例如,您可以使用高位ASCII数据或字对齐指针的低字节。
或者,您可以在没有任何额外位的情况下执行此操作,费用为多项式时间。反转计算,以便找到最终数组中每个项目的原始源索引。
source = i % groupSize + groupSize * (i/groupSize) ; //integer division
现在向前走过数组,用源中的一个交换每个项目。诀窍是,只要源索引小于当前位置(意味着它已被换出),您需要跟踪路径,直到找到其当前位置
getSource(i):
s = i % groupSize + groupSize * (i/groupSize)
while (s<i)
s = s % groupSize + groupSize * (s/groupSize)
return s
shuffle:
for i in (0..N-1)
swap(a[i],a[getSource(i)]
答案 3 :(得分:0)
你可以肯定地做到这一点 - 只需将卡牌ace,2,... 5套装成三件套装并按顺序排列。
首先取出a2卡并将其放在一边。 然后将b1移动到a2位置并将所有卡向上移动
然后你放回a2卡并放入移出的位置。
然后你拿出a3卡和puti taside 将c1移动到a3位置并向上移动所有卡片。
然后将a3卡放回空位。
重复直到完成。
指数的实际计算是棘手的,但我相信之前的海报已经做到了这一点。