这篇文章讨论了块交换算法。它用于将一个数组旋转任意数量的位置,其时间复杂度为O(N),空间复杂度为O(1)。
目录:
- 阵列旋转的问题陈述
- 区块互换算法
- 例子区块交换算法的试运行
- 区块互换算法的实现
- 区块互换算法的时间复杂度
- 区块互换算法的空间复杂度
让我们开始学习区块交换算法。
阵列旋转的问题声明
在我们讨论算法之前,我们必须先看看旋转数组的实际含义是什么。一个数组可以在任何方向(左或右)旋转任意次数。
假设A=[1,2,3,4,5] 。
向左旋转一次。A = [2,3,4,5,1]
向右旋转一次。A = [5,1,2,3,4]
向左旋转三个位置。A = [4,5,1,2,3]
另外,请注意,向左旋转D次,相当于向右旋转N次。
因为,A=[1,2,3,4,5]。
向左旋转2位。A = [3,4,5,1,2].
这相当于向右旋转3次(N - D => 5-2 = 3)。A = [3,4,5,1,2].
有许多方法来旋转一个数组。一些方法需要辅助空间,而另一些方法需要对数组进行一次以上的遍历。然而,块交换算法提供了一种有效的方法来执行旋转操作。我们将在本文中详细讨论它。
反转算法提供了另一种相同的方法。请参考这篇文章,以获得一个良好的洞察力。
区块互换算法
区块交换算法的步骤是。
-
将数组分为两部分,A = arr[0...d-1],B = arr[d...n-1]。
-
当A的大小不等于B的大小时,这样做:
2.1 如果A的大小小于B,用B的一个大小等于A的子数组交换A,并且不与A相邻。 -
交换A和B
让我们详细了解一下步骤2。
在2.1中,A的大小小于B的大小,所以我们将A与B中的一个子数交换,使其与A的大小相同,并且不与A相邻。
对于arr = [A][B] 和B = [B1][B2] => arr = [A][B1][B2] 其中B2的大小等于A的大小,我们将[A]和[B2]交换,结果Arr = [B2][B1][A] 。
现在,[A]在它的正确位置。继续计算arr = [B2][B1]。
在2.2中,B的大小小于A的大小,所以我们将B与A中的一个子数交换,使其与B的大小相同,并且不与B相邻。
对于arr = [A][B] 和A = [A1][A2] => arr = [A1][A2][B] 其中A1的大小等于B的大小,我们将[A1]和[B]交换,其结果是arr = [B][A2] [A1] 。现在,[B]在它的正确位置。继续计算arr = [A2][A1]。
例子:区块互换算法的试运行
考虑arr = [1,2,3,4,5], N = 5, d = 2.
步骤1:A = arr[0...1] = [1,2] & B = arr[2...4] = [3,4,5]
第2步:由于大小(A)<大小(B),将A与B2交换,其中B2 = [4,5] & B1 = [3]。因此,A = [B2] = [4,5] ,B = [B1][A] = [3,1,2]。
现在,继续计算[4,5,3],它对应于[B2][B1],因为[A]是在它的最终位置。
A = arr[0...1] = [4,5] & B = [2...2] = [3]
由于大小(A)>大小(B),用A1交换B,A1 = [4] & A2 = [5]。所以,A1 = [B] = [3] & B = [A1] = 4。而arr = [3,5,4] = [B][A2][A1] 。
现在,对[A2][A1]=[5,4]进行递归。
所以,对于这次迭代,arr = [5,4], N = 2, d = 2.因为,d==N,所以返回数组。
因此,结果数组是[3,5,4,1,2],这也是预期结果。
区块互换算法的实现
以下是块交换算法在Java中的实现:
public static void rotate(int arr[], int i, int d, int n)
{
if(d == 0 || d == n)
return;
if(d == n-d) //Size of both the arrays is equal
{
swap(arr, i, n - d + i, d); //swap(arr, i, i+d);
return
}
if(d < n-d)
{
swap(arr, i, n-d+i, d);
rotate(arr, i, d, n-d);
}
else
{
swap(arr, i, d, n-d);
rotate(arr, n-d+i, 2*d - n,d);
}
}
public static void swap(int arr[], int s, int e, int d)
{
for(int i=0;i<d;i++)
{
int temp = arr[s + i];
arr[s + i] = arr[e + i];
arr[e + i] = temp;
}
}
以下是区块交换算法在Java中的实现:
void rotate(int arr[], int i, int d, int n)
{
if(d == 0 || d == n)
return;
if(d == n-d) //Size of both the arrays is equal
{
swap(arr, i, n - d + i, d); //swap(arr, i, i+d);
return
}
if(d < n-d)
{
swap(arr, i, n-d+i, d);
rotate(arr, i, d, n-d);
}
else
{
swap(arr, i, d, n-d);
rotate(arr, n-d+i, 2*d - n,d);
}
}
void swap(int arr[], int s, int e, int d)
{
for(int i=0;i<d;i++)
{
int temp = arr[s + i];
arr[s + i] = arr[e + i];
arr[e + i] = temp;
}
}
区块互换算法的时间复杂度
这个算法需要O(N)时间。
这是因为,在每次迭代中,我们交换d个元素,之后d个元素会出现在它们的正确位置。剩余的n-d个元素被传递给下一个函数调用,同样的操作被重复,直到d变成等于n-d。这表明时间复杂度将是O(N),每个元素至少被交换一次。
块交换算法的空间复杂度
没有使用辅助空间,所以块交换算法的空间复杂度是O(1)。
通过OpenGenus的这篇文章,你一定对块交换算法有了完整的了解。