作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址: https://leetcode.com/problems/couples-holding-hands/description/

题目描述:

N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and switch seats.

The people and seats are represented by an integer from 0 to 2N-1, the couples are numbered in order, the first couple being (0, 1), the second couple being (2, 3), and so on with the last couple being (2N-2, 2N-1).

The couples’ initial seating is given by row[i] being the value of the person who is initially sitting in the i-th seat.

Example 1:

Input: row = [0, 2, 1, 3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.

Example 2:

Input: row = [3, 2, 0, 1]
Output: 0
Explanation: All couples are already seated side by side.

Note:

  1. len(row) is even and in the range of [4, 60].
  2. row is guaranteed to be a permutation of 0…len(row)-1.

题目大意

有0~N-1这些数字的排列组成的一个数组,0和1,2和3,…,N-2和N-1分别是情侣,现在要让情侣坐在一起,每次能交换两个人的座位,求最少需要换多少次座位。

解题方法

这个题不愧是Hard题,虽然题目简单,但是没有任何思路。

看了Grandyang大神的做法,使用贪心策略。直接找出第偶数个位置是否和他的另一半在一起,是的话不用交换,否则找出另一半在哪里,然后直接把现在和自己坐在一起的人与自己的另一半的位置交换即可。(不会证明)

原文是:

当我们暂时对如何用代码来解决问题没啥头绪的时候,一个很好的办法是,先手动解决问题,意思是,假设这道题不要求你写代码,就让你按照要求排好序怎么做。我们随便举个例子来说吧,比如:

[3 1 4 0 2 5]

我们如何将其重新排序呢?首先明确,我们交换数字位置的动机是要凑对儿,如果我们交换的两个数字无法组成新对儿,那么这个交换就毫无意义。来手动交换吧,我们两个两个的来看数字,前两个数是3和1,我们知道其不成对儿,数字3的老相好是2,不是1,那么怎么办呢?我们就把1和2交换位置呗。好,那么现在3和2牵手成功,度假去了,再来看后面的:

[3 2 4 0 1 5]

我们再取两数字,4和0,互不认识!4跟5有一腿儿,不是0,那么就把0和5,交换一下吧,得到:

[3 2 4 5 1 0]

好了,再取最后两个数字,1和0,两口子,不用动!前面都成对的话,最后两个数字一定成对。而且这种方法所用的交换次数一定是最少的。

使用了一个很高效的求另一半的方式,使用1异或。如果是偶数的话,最后位是0,‘异或’上1等于加了1,变成了可以的成对奇数。如果是奇数的话,最后位是1,‘异或’上1后变为了0,变成了可以的成对偶数。

最坏情况下的时间复杂度是O(N^2),空间复杂度是O(1)。

class Solution(object):
def minSwapsCouples(self, row):
"""
:type row: List[int]
:rtype: int
"""
res = 0
n = len(row)
for i in range(0, n - 1, 2):
if row[i + 1] == (row[i] ^ 1):
continue
for j in range(i + 1, n):
if row[j] == (row[i] ^ 1):
row[j], row[i + 1] = row[i + 1], row[j]
res += 1
return res

另外一个解法,是使用并查集。但是这个解法我没有看懂,所以只贴上代码,不讲解了。

class Solution(object):
def minSwapsCouples(self, row):
"""
:type row: List[int]
:rtype: int
"""
n = len(row)
cnt = n / 2
self.par = range(n)
for i in range(0, n, 2):
x = self.find(row[i] / 2)
y = self.find(row[i + 1] / 2)
if x != y:
self.par[x] = y
cnt -= 1
return n / 2 - cnt def find(self, x):
return x if self.par[x] == x else self.find(self.par[x])

参考资料:

http://www.cnblogs.com/grandyang/p/8716597.html

日期

2018 年 10 月 1 日 —— 欢度国庆!

【LeetCode】765. Couples Holding Hands 解题报告(Python)的更多相关文章

  1. [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 ...

  2. 【LeetCode】62. Unique Paths 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址:https://leetcode.com/problems/unique-pa ...

  3. 【LeetCode】376. Wiggle Subsequence 解题报告(Python)

    [LeetCode]376. Wiggle Subsequence 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.c ...

  4. 【LeetCode】649. Dota2 Senate 解题报告(Python)

    [LeetCode]649. Dota2 Senate 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地 ...

  5. 【LeetCode】911. Online Election 解题报告(Python)

    [LeetCode]911. Online Election 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ ...

  6. 【LeetCode】886. Possible Bipartition 解题报告(Python)

    [LeetCode]886. Possible Bipartition 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu ...

  7. 【LeetCode】36. Valid Sudoku 解题报告(Python)

    [LeetCode]36. Valid Sudoku 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址 ...

  8. 【LeetCode】870. Advantage Shuffle 解题报告(Python)

    [LeetCode]870. Advantage Shuffle 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn ...

  9. 【LeetCode】593. Valid Square 解题报告(Python)

    [LeetCode]593. Valid Square 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地 ...

随机推荐

  1. 类成员函数调用delete this会发生什么呢?

    有如下代码 class myClass { public: myClass(){}; ~myClass(){}; void foo() { delete this; } }; int main() { ...

  2. 2019java面试

    1.面向对象的特征有哪些方面?答:面向对象的特征主要有以下几个方面:    抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...

  3. (数据科学学习手札132)Python+Fabric实现远程服务器连接

    本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 日常工作中经常需要通过SSH连接到多台远程 ...

  4. CSS3实现字体描边

    CSS3实现字体描边的两种方法 -webkit-text-stroke: 1px #fff;:不建议,向内描边,字体颜色变细,效果不佳: 用box-shadow模拟描边,向外描边,保留字体粗细,赞! ...

  5. 日常Java测试第二段 2021/11/12

    第二阶段 package word_show; import java.io.*;import java.util.*;import java.util.Map.Entry; public class ...

  6. Kafka 集群安装部署

    2.1 安装部署 2.1.1 集群规划 192.168.1.102 192.168.1.103 192.168.1.104 zookeeper zookeeper zookeeper kafka ka ...

  7. Shell学习(三)——Shell条件控制和循环语句

    参考博客: [1]Shell脚本的条件控制和循环语句 一.条件控制语句 1.if语句 1.1语法格式: if [ expression ] then Statement(s) to be execut ...

  8. Linux磁盘分区(一)之fdisk命令

    Linux磁盘分区(一)之fdisk命令转自:https://www.cnblogs.com/machangwei-8/p/10353683.html 一.fdisk 的介绍fdsik 能划分磁盘成为 ...

  9. jenkins之授权和权限管理

    #:创建角色,给角色授权,然后创建用户,将用户加入到角色(前提先安装插件) #:先将之前的卸载掉 #:然后重启服务,在可选插件搜索Role #:装完重启服务 root@ubuntu:~# system ...

  10. Oracle trunc和round的区别

    1.关于trunc 和round函数比较 整体概括: round函数 四舍五入trunc函数 直接截取 对于时间: Round函数对日期进行"四舍五入",Trunc函数对日期进行截 ...