原文见:https://leetcode.com/problems/couples-holding-hands/discuss/113362/JavaC%2B%2B-O(N)-solution-using-cyclic-swapping

一、问题引入

假设有一个长度为N的数组nums包含0—N-1的所有数字,但是数组中数字的顺序是随机的。可以任选两个数字进行交换,问最少要用多少步能够使数组满足 i==nums[i](即使数组递增有序)。

二、Cyclic Swapping

使用cyclic swapping的解法:

1.第一步是将N个下标划分为互斥的几个group,每个group是一个环:i0 --> i1 --> ... --> ik --> i0,

其中i0-->i1表示下标为i0的元素应放在i1的位置(即nums[i0]==i1)。

例子:

    row: 2, 3, 1, 0, 5, 4

    idx:  0, 1, 2, 3, 4, 5

对于上例:

  nums[0]=2, 得0-->2;nums[2]=1,得2-->1;nums[1]=3,得1-->3;nums[3]=0,得3-->0;

  综上得:0-->2-->1-->3-->0;

  同理还可得:4-->5-->4。

这一步的算法:对任意数组nums,对于一个未访问过的下标i0,计算i1使得nums[i0]==i1,接着从i1开始计算i2使得nums[i1]==i2,以此下去,得到 i0 --> i1 --> i2 --> ... --> ik。需要证明该链会从i0开始循环。

此时需证明:

1.最终i0 --> i1 --> i2 --> ... --> ik会循环。

2.且这个环从i0开始循环。

如下图:

证明1:如果i0 --> i1 --> i2 --> ... --> ik 不会形成环,按照该链生成的规则一直生成下一个i,那么最终会生成一个含有N+1个元素的链,这与题目矛盾。所以该链一定是一个环。

证明2:假设环从一个不为i0的下标j开始循环,那么会形成下图所示,i2-->j且im-->j,则nums[i2]==nums[im],这与题设矛盾。所以该环一定从i0开始循环。

假设现在有两个不同的group,那么两个group一定互斥。因为如果两个group中都存在一个下标j,那么可以根据之前提到的group的生成算法从j开始构造两个group,又因为生成的每一个index仅与它的前驱有关(index==nums[pre]),所以生成的两个group一定是一样的。

2.要使大小为k的group有序(nums[i]==i),最少需要k-1步。group的大小定义为group环中元素个数。

使用数学归纳法证明:

1) 假设group的大小为1,代表已经满足nums[i]==i,需要0步使其有序。所需步数为group的大小减1.

2) 假设group的大小为m时,需m-1步使之有序(1 <= m <= k)

3) 对于大小为k+1的group而言,可以使用一次交换操作将其划分为两个互斥的group1和group2,大小分别为k1和k2,k1+k2==k+1,1 <= k1, k2 <= k:任选下标i和j,将nums[i]和nums[j]交换,交换效果如下图:

因为2)的缘故,解决group1需要k1-1步,解决group需要k2-1,故解决group的步数为

k1-1+k2-1+1 == k1+k2-1 == k+1-1 == k;

得证:使大小为k的group有序,最少需要k-1步。

综上所述,通过对解决每个group所需的最小交换数求和,可以得到使整个数组有序所需的最小交换数。为了解决每个group,我们可以任意地在group中选择任意两个不同的index并交换indexs上的元素,从而将group缩减为两个较小的不相交的group。在实践中,我们总是可以选择一个pivot,并不断地与它的期望的index交换,直到pivot上的数与期望index相同为止,这意味着整个group被解决,group内的所有nums[i]==i。


相关题目:

leetcode 41 fisrt missing positive: https://www.cnblogs.com/jasonlixuetao/p/10776564.html

leetcode 268 missing number:https://www.cnblogs.com/jasonlixuetao/p/10776701.html

cyclic swapping algorithm的更多相关文章

  1. leetcode_41. First Missing Positive_cyclic swapping

    https://leetcode.com/problems/first-missing-positive/ 给定一个长度为len的无序数组nums,找到其第一个丢失的正整数. 解法: 使用cyclic ...

  2. leetcode_268.missing number

    给定一个数组nums,其中包含0--n中的n个数,找到数组中没有出现的那个数. 解法一:cyclic swapping algorithm class Solution { public: int m ...

  3. LeetCode765. Couples Holding Hands

    N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum numb ...

  4. [LeetCode] 765. Couples Holding Hands 情侣牵手

    N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum numb ...

  5. [codeforces 901E] Cyclic Cipher 循环卷积-Bluestein's Algorithm

    题目大意: 传送门 给两个数列${B_i}.{C_i}$,长度均为$n$,且${B_i}$循环移位线性无关,即不存在一组系数${X_i}$使得对于所有的$k$均有$\sum_{i=0}^{n-1} X ...

  6. codeforces 709C C. Letters Cyclic Shift(贪心)

    题目链接: C. Letters Cyclic Shift 题意: 现在一串小写的英文字符,每个字符可以变成它前边的字符即b-a,c-a,a-z这样,选一个字串变换,使得得到的字符串字典序最小; 思路 ...

  7. algorithm之改变序列算法--待解决

    简述:改变序列算法,参见http://www.cplusplus.com/reference/algorithm/?kw=algorithm 待解决问题:iterator_traits.std::mo ...

  8. hdu 1853 Cyclic Tour 最小费用最大流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 There are N cities in our country, and M one-way ...

  9. [POJ 1674] Sorting by Swapping

    Sorting by Swapping Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9514   Accepted: 50 ...

随机推荐

  1. [POI 2007] 办公楼

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1098 [算法] 显然 , 答案为补图的连通分量个数 用链表优化BFS , 时间复杂度 ...

  2. JSON --- 一种轻量级的数据交换格式

    目录 1. 语法 2. 解析与序列化 JSON.stringify( jsData[, filter, indent] ) JSON.parse( jsonData[, reduction]) JSO ...

  3. CKD 实现

    主要功能: 1.新物料(部品号)的入库管理 部品号的验证.描述.品名.重量.单价等 2.部品号-供应商的核对 校验部品号/供应商的对应情况.入库.移除等 3.BOM清单的导入 基础清单的导入 4.订单 ...

  4. ibatis 中 $与#的区别

    ibatis 中 $与#的区别 使用#: select * from table where id = #id# 如果字段为整型:#id#表示成id select * from table where ...

  5. python接口自动化(三十八)-python操作mysql数据库(详解)

    简介 现在的招聘要求对QA人员的要求越来越高,测试的一些基础知识就不必说了,来说测试知识以外的,会不会一门或者多门开发与语言,能不能读懂代码,会不会Linux,会不会搭建测试系统,会不会常用的数据库, ...

  6. bzoj 3053: The Closest M Points【KD-tree】

    多维KDtree板子 左右儿子的估价用mn~mx当区间,假设区间里的数都存在:k维轮着做割点 #include<iostream> #include<cstdio> #incl ...

  7. Spring boot整合redis实现shiro的分布式session共享

    我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分 ...

  8. 函数和代码复用 --Python

    1.关于递归函数的描述,以下选项中正确的是 A.包含一个循环结构 B.函数比较复杂 C.函数内部包含对本函数的再次调用 D.函数名称作为返回值 答案:D 答案解析:递归函数是指函数内部包含对本函数的再 ...

  9. Java关键字abstract与final总结

    关键字:abstract 用来修饰抽象类与抽象类中的方法 抽象类需要注意的几点: 抽象类不能被实例化.抽象类可以包含属性:方法:构造方法,但是构造方法不能用来new实例,只能被子类调用 有抽象方法的类 ...

  10. 4-redis数据过期策略

    1 基本 redis也许只是用来存放临时数据.比如股市行情.游戏中一个持续一个月的活动等,都属于缓存数据,过了一段就没用了.如果没有过期策略,就会有大量垃圾数据在内存中堆积. 2 TTL time t ...