1
7
这是可能的,但它是非常复杂的!一个更简单的O(nlogn)和O(1)空间解决方案在代码和缓存方面可能更好。 我们会解决一个与你不同的问题,但一旦我们解决了这个问题,你的问题就微不足道了。 将数组视为
你必须把这个转换成
使用指数1到2n, 我们看到这是由
O(nlogn)时间O(1)空间解决方案 我们可以用分而治之的方法。 首先是一些接近n/2转换的m
到
通过递归地应用到前2米元素,然后应用到其余元素。 现在我们需要做的就是将中间的数组循环移动m个点(这可以在o(n)时间和o(1)空间中完成)。 给予
当然,正如ivlad指出的,这需要O(logn)堆栈空间。我们可以通过以下步骤来解决这个问题: 我们有:
现在交换数组后半部分中的对
现在循环移动奇数位置的元素:
这给了
现在再次交换数组的后一部分
现在递归求解第一部分和第二部分给出
无论2M>=N与否,这都有效。 所以,这是O(nlogn)时间和O(1)空间算法。 O(N)时间O(1)空间解。 使用的想法与以下文章中使用的想法类似: A simple in-place algorithm for Inshuffle . 你需要阅读那篇论文才能理解下面的内容。我建议你也阅读: How to master in-place array modification algorithms? 这基本上就是上面这篇文章所解决的逆排列。 当2n+1是3的幂(比如说3^m)时,就足以解决这个问题,因为我们可以在这之后使用分而治之(比如o(nlogn)解决方案)。 现在2n+1和n+1是相对质数,所以工作模为3^m,我们看到n+1 必须 成为2的力量。(再看那篇论文,看看为什么:基本上,任何数模3^m,相对于3^m是2的幂,同样是模3^m)。 假设n+1=2^k(我们还不知道k,注意这是3^m的模)。 求k的一种方法,计算n+1模3^m的幂,直到它变成1。这给了我们K(最多是O(N)时间)。 现在我们可以看到排列的循环(参见上面的paper/stackoverflow链接了解它是什么)开始于 2 ^ a* 3 ^ b 其中0<=a<k和0<=b<m。 所以你从每一对(A,B)开始,遵循排列的循环,这给了一个O(N)时间,就地算法,因为你接触每一个元素的次数不超过一个常数! 这有点简短!!)如果你需要更多信息,请告诉我。 |
2
3
你所得到的是一个n x 2矩阵,用一维数组表示,你想把它转换成一个2x n数组。 例如,您的列表: 一 一 ,B 一 A 二 ,B 二 ,…一 n ,B n 也可以用矩阵表示: X 1,1 ,X 1,2 ,X 2,1 ,X 2,2 ,…X n,1 ,X n,2 你想转置成: X 1,1 ,X 2,1 ,…X n,1 ,X 1,2 ,X 2,2 ,…X n,2 这个 in place matrix transposition algorithm 会完成任务的。 编辑 好的,让我把它拼出来。尝试以下代码位:
这将打印出需要交换的数组元素。这将适用于线性数组中表示的任何大小的矩阵,其中元素按列排列,然后按行排列。使用n x 2 martix,元素排列如下: X 1,1 ,X 1,2 ,X 2,1 ,X 2,2 ,…X n,1 ,X n,2 该算法打印出需要交换的元素,以生成一个按如下顺序排列的数组: X 1,1 ,X 2,1 ,…X n,1 ,X 1,2 ,X 2,2 ,…X n,2 例如,从r=4,c=2开始,数组:
需要以下交换:
成为:
该算法在空间和时间上都是有效的。 海上舞台 我的O-foo不太好,但我会试一试… 矩阵包含两列(“a”和“b”)和“m”行。将其表示为 一个线性阵列,我们需要2米的元素。让我们调用这个数字n(线性数组的大小)。 该算法有两个迭代循环,一个用于“r”(行),另一个用于“c”(列)。 总的迭代次数是r*c,在我们的例子中是2 m=n,到目前为止还不错。
外卡是内在的
关于
需要多少个交换?交换次数限制为每次迭代通过外部 两个循环,最多N次。交换次数与O(N)性能一致。 我的猜测是这是一个非O(N)算法,但似乎有合理的行为 对于中等大小的2列矩阵。 以下是各种2列矩阵大小的一些经验结果:
“每行循环数”随着行数的增加而增加,但不会以惊人的速度增长。危险的是它会达到指数级的“最佳”位置——但我不知道它是否真的有这种潜力。 我对MGCCL的建议是在行计数范围内对该算法进行基准测试 在他的应用中很典型,然后决定它是否会产生一个可接受的性能相对于其他 算法基准。Big-O分析 很有趣,但是在一个操作数据范围内的结果才是重要的。 最后一脚在罐子上: 为什么这个算法有效? 转置以线性形式表示的矩阵: 给定矩阵x有m行和n列。 将x按行主顺序排列成一个线性数组。这个 阵列的组织方式如下:
描述线性数组中每个元素的符号 是: X[i,r,c] where: i is the linear array index for element X r is the row number for element X c is the column number for element X. 用这个符号, 按行主顺序排列的数组可以生成为:
请注意,给定的j(行)和k(列)值,i可计算为:
矩阵x的转置是通过交换元素构造的。 x[i,r,c]和x[t,c,r]在r和c的范围内。本质上,我们交换 列变量的所有行变量。使用符号 如上所述,这相当于交换线性阵列元素: exchange(X[i,r,c], X[t,c,r]) where: i = (r - 1) * N + c t = (c - 1) * M + i 转置矩阵所需的交换次数将小于 m*n是因为最多需要一次交换才能将一个元素放入其正确的元素中。 位置。在某些情况下,不需要交换,因为 元素已“就位”。例如x的第一个和最后一个元素 不需要交换。 通过增加i继续通过线性阵列,我们知道只要 所有的交换都不涉及I>T,矩阵将在其中 索引小于或等于i的所有元素的列主顺序。 每当I>T时,这意味着之前在指数T进行了交换。 如上文所示,在t处交换元素。 在某个新的位置t’。给定一个索引t,我们可以计算行主索引t' 以及与之关联的行和列编号,如下所示:
同样,如果t'小于i,这意味着这个元素也被交换了,我们必须 继续进行另一轮计算。将t设置为计算的t'并重复。 最终,我会变成 交换可以完成。基本上,我们“追逐”元素的所有 之前的交换,直到我们在i或i的右边找到它为止。 数组。 对线性数组中的每个元素重复此循环,矩阵将 被调换了。 |
3
0
o(1)时间,o(1)额外空间
输出: <0:44961, 1:246, 2:54618, 3:41468, 4:12646, 5:21691, 6:26697, 7:36409> <0:44961, 1:54618, 2:12646, 3:26697, 4:246, 5:41468, 6:21691, 7:36409> |
4
0
好吧,让我们看看这个例子: 0 1 2 3 4 5 6 7 8 9 10 0 2 4 6 8 10 1 3 5 7 9 结果的前半部分包含元素,其索引为原始索引i的i/2,而另一半是i-n/2+1,其中n是数组中的项数。 这基本上是排序算法的一种特殊情况,只是设置了一个特殊的顺序。 所以这里有一个使用冒泡排序算法对整数数组排序的想法。我们需要的是将偶数值拉到开头,留下奇数值:
但是,只有在您可以保留索引(即在本例中,索引与数组值相关联)的情况下,这才有效。BubbleSort的性能为O(n^2),内存使用率为1。 它不能在O(n)时间和1内存中完成[编辑:仅使用通用排序算法!],在o(nlog n)中执行的最佳通用排序算法: http://en.wikipedia.org/wiki/Sorting_algorithm 要解决您的问题,最好的方法是生成一系列符合您标准的索引:
然后简单地使用它将原始数组中的项映射到新位置:
这个东西可以在O(N)中运行,但也需要O(N)内存。但是,如果sizeof类型比sizeof int大得多,那么它仍然是内存使用量的增加(而不是复制类型对象)。 [编辑2] 除了需要将原始向量复制到类的实例中的漂亮的oop代码anddo之外,您可以简单地编写一个函数:
当你需要得到排列值的时候就使用它。实际上,这只需要O(n)次时间,因为对于给定的向量(至少在一个完整的“for each”循环中),Permutted_索引的计算结果不会超过N次。 |
danial · 如何在多个字符串的每个位置找到最频繁的字符 2 年前 |
Manny · 如何比较Perl中的字符串? 2 年前 |
Diret · 获取范围内每个数字的子倍数的算法 2 年前 |
Saif · 排序时python如何决定何时调用比较器? 2 年前 |