我正在整理,没有编号相同的整数序列(不失一般性,我们假设该序列的排列1,2,...,n
)为它的自然递增的顺序(即1,2,...,n
)。 我在想直接交换的元素(无论元件的位置的;换言之,一个交换是有效的任何两个元素)与交换的最小数目(以下可以是一个可行的解决方案):
交换与它们中的任一者或两者应当被交换到正确的位置(一个或多个)的约束的两个元素。 直到每一个元素都放在正确的位置。
但我不知道如何数学证明,如果上述方案是最优的。 任何人都可以帮助吗?
我正在整理,没有编号相同的整数序列(不失一般性,我们假设该序列的排列1,2,...,n
)为它的自然递增的顺序(即1,2,...,n
)。 我在想直接交换的元素(无论元件的位置的;换言之,一个交换是有效的任何两个元素)与交换的最小数目(以下可以是一个可行的解决方案):
交换与它们中的任一者或两者应当被交换到正确的位置(一个或多个)的约束的两个元素。 直到每一个元素都放在正确的位置。
但我不知道如何数学证明,如果上述方案是最优的。 任何人都可以帮助吗?
我能够与证明这个图形理论 。 可能要添加标签的:)
创建一个图表n
顶点。 创建从节点的边n_i
到n_j
如果在位置上的元素i
应在位置j
在正确的排序。 现在,您将拥有由几个不相交的周期的图表。 我认为,需要互换的最小数目订购的图形正确地是
M = sum (c in cycles) size(c) - 1
花一秒钟去说服那自己......如果两个项目是在一个周期内,一个是swap可以只照顾他们。 如果三个项目都在一个周期内,你可以换一对把一个在正确的位置,和两个周期仍然存在,等等。如果n
项目是在一个周期内,你需要n-1
互换。 (这始终是真实的,即使你不近邻交换。)
鉴于这种情况,你现在也许可以明白为什么你的算法是最优的。 如果你做了交换和至少一个项目是在正确的位置,那么它会一直减少的价值M
加1。对于长度的任何周期n
,可以考虑换一个元素到正确的位置,它的邻居占用。 您现在有一个正确排序的元素,和长度的周期n-1
由于M
是互换的最小数目,以及你的算法总是降低M
以1为每个交换,它必须是最优的。
供您参考,这里是一个算法,我写的,生成的数组排序需要交换的最小数目。 它发现通过@Andrew毛描述的循环。
/**
* Finds the minimum number of swaps to sort given array in increasing order.
* @param ar array of <strong>non-negative distinct</strong> integers.
* input array will be overwritten during the call!
* @return min no of swaps
*/
public int findMinSwapsToSort(int[] ar) {
int n = ar.length;
Map<Integer, Integer> m = new HashMap<>();
for (int i = 0; i < n; i++) {
m.put(ar[i], i);
}
Arrays.sort(ar);
for (int i = 0; i < n; i++) {
ar[i] = m.get(ar[i]);
}
m = null;
int swaps = 0;
for (int i = 0; i < n; i++) {
int val = ar[i];
if (val < 0) continue;
while (val != i) {
int new_val = ar[val];
ar[val] = -1;
val = new_val;
swaps++;
}
ar[i] = -1;
}
return swaps;
}
斯威夫特4版:
func minimumSwaps(arr: [Int]) -> Int {
struct Pair {
let index: Int
let value: Int
}
var positions = arr.enumerated().map { Pair(index: $0, value: $1) }
positions.sort { $0.value < $1.value }
var indexes = positions.map { $0.index }
var swaps = 0
for i in 0 ..< indexes.count {
var val = indexes[i]
if val < 0 {
continue // Already visited.
}
while val != i {
let new_val = indexes[val]
indexes[val] = -1
val = new_val
swaps += 1
}
indexes[i] = -1
}
return swaps
}
做得好的@bekce解决方案。 如果使用C#,建立修改的数组的初始代码ar
可以简洁地表述为:
var origIndexes = Enumerable.Range(0, n).ToArray();
Array.Sort(ar, origIndexes);
然后用origIndexes
代替ar
在代码的其余部分。
//假设我们正在处理的只是顺序启动零
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start) {
j = arr[j]
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
EHM,所有的循环计数是很难保持在你的脑袋。 还有一种方式,就是要简单得多记忆。
首先,让我们去手动抛出一个样本案例。
swap(0,2);swap(0,3)
是相同的swap(2,3);swap(0,2)
swap(0, 1)
=> [(3,2),(1,1),(2,3),(4,4),(5,5),(6,6),(0,7) ] swap(0, 3)
=> [(4,4),(1,1),(2,3),(3,2),(5,5),(6,6),(0,7) ] swap(0, 4)
=> [(5,5),(1,1),(2,3),(3,2),(4,4),(6,6),(0,7) ] swap(0, 5)
=> [(6,6),(1,1),(2,3),(3,2),(4,4),(5,5),(0,7) ] swap(0, 6)
=> [(0,7),(1,1),(2,3),(3,2),(4,4),(5,5),(6,6) ] 即语义你的元素进行排序,然后找出如何通过通过是不合时宜的最左边的项目交换他们把到初始状态。
Python的算法是如此简单:
def swap(arr, i, j):
tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
def minimum_swaps(arr):
annotated = [*enumerate(arr)]
annotated.sort(key = lambda it: it[1])
count = 0
i = 0
while i < len(arr):
if annotated[i][0] == i:
i += 1
continue
swap(annotated, i, annotated[i][0])
count += 1
return count
因此,你不需要记住访问节点,也没有计算一些周期长。
这是在C代码示例++,用于查找互换的最小数目来排序的序列的置换(1,2,3,4,5,.......n-2,n-1,n)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,i,j,k,num = 0;
cin >> n;
int arr[n+1];
for(i = 1;i <= n;++i)cin >> arr[i];
for(i = 1;i <= n;++i)
{
if(i != arr[i])// condition to check if an element is in a cycle r nt
{
j = arr[i];
arr[i] = 0;
while(j != 0)// Here i am traversing a cycle as mentioned in
{ // first answer
k = arr[j];
arr[j] = j;
j = k;
num++;// reducing cycle by one node each time
}
num--;
}
}
for(i = 1;i <= n;++i)cout << arr[i] << " ";cout << endl;
cout << num << endl;
return 0;
}
与在Java基本类型(和测试)的整数的实现。
import java.util.Arrays;
public class MinSwaps {
public static int computate(int[] unordered) {
int size = unordered.length;
int[] ordered = order(unordered);
int[] realPositions = realPositions(ordered, unordered);
boolean[] touchs = new boolean[size];
Arrays.fill(touchs, false);
int i;
int landing;
int swaps = 0;
for(i = 0; i < size; i++) {
if(!touchs[i]) {
landing = realPositions[i];
while(!touchs[landing]) {
touchs[landing] = true;
landing = realPositions[landing];
if(!touchs[landing]) { swaps++; }
}
}
}
return swaps;
}
private static int[] realPositions(int[] ordered, int[] unordered) {
int i;
int[] positions = new int[unordered.length];
for(i = 0; i < unordered.length; i++) {
positions[i] = position(ordered, unordered[i]);
}
return positions;
}
private static int position(int[] ordered, int value) {
int i;
for(i = 0; i < ordered.length; i++) {
if(ordered[i] == value) {
return i;
}
}
return -1;
}
private static int[] order(int[] unordered) {
int[] ordered = unordered.clone();
Arrays.sort(ordered);
return ordered;
}
}
测试
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MinimumSwapsSpec {
@Test
public void example() {
// setup
int[] unordered = new int[] { 40, 23, 1, 7, 52, 31 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(5, minSwaps);
}
@Test
public void example2() {
// setup
int[] unordered = new int[] { 4, 3, 2, 1 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
@Test
public void example3() {
// setup
int[] unordered = new int[] {1, 5, 4, 3, 2};
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
}
雨燕4.2:
func minimumSwaps(arr: [Int]) -> Int {
let sortedValueIdx = arr.sorted().enumerated()
.reduce(into: [Int: Int](), { $0[$1.element] = $1.offset })
var checked = Array(repeating: false, count: arr.count)
var swaps = 0
for idx in 0 ..< arr.count {
if checked[idx] { continue }
var edges = 1
var cursorIdx = idx
while true {
let cursorEl = arr[cursorIdx]
let targetIdx = sortedValueIdx[cursorEl]!
if targetIdx == idx {
break
} else {
cursorIdx = targetIdx
edges += 1
}
checked[targetIdx] = true
}
swaps += edges - 1
}
return swaps
}
我们并不需要交换的实际元素,只要找到多少个元素在右指数(循环)都没有。 最小互换将是周期 - 1; 下面是代码...
static int minimumSwaps(int[] arr) {
int swap=0;
boolean visited[]=new boolean[arr.length];
for(int i=0;i<arr.length;i++){
int j=i,cycle=0;
while(!visited[j]){
visited[j]=true;
j=arr[j]-1;
cycle++;
}
if(cycle!=0)
swap+=cycle-1;
}
return swap;
}