【力扣765】情侣牵手
情人节做一道虐狗思维题蛤蛤
原题:
这题第一眼看上去很眼熟
我们都做过这道题的排序版本,即一个乱序序列,让你把它排成升序的
在排序版本中用的是贪心算法,那么这道题也可以从贪心的角度考虑
研究题目性质,发现:
1.两对情侣必须坐在下标异或为 1 的位置上,也就是说如果一个人在 i ,那么他的对象一定在 i ^ 1
这个性质表明数在序列中的位置是没有意义的,整个序列可以看成 n 个二元组,只考虑二元组中有哪两个人
2.对于某个人来说,其余的人只有两种人,他的对象和其他人
依据这两个性质就可以进行贪心了
根据性质1,可以从左到右扫描每个二元组,如果已经成对就不动,否则交换其中的一人,易证同时交换两人不会更优
接着考虑被换掉的人换到哪里
猜想一个策略,如果存在位置可以同时成全两对,即 ab ba 这种形式,那必然成全两对,否则就只成全任意一个
这样做是对的,因为根据性质2,除非被换掉的人能换到对象旁边,否则换和不换,换到谁旁边都一样,只要成全没被换掉的人就更优
代码:(力扣的提交代码规则很奇怪,输入输出由函数的参数和返回值给出,可能这是面试惯用方法吧)
1 class Solution { 2 public: 3 inline bool checkCouple(int person1, int person2) { 4 return ((person1 ^ person2) == 1); 5 } 6 int minSwapsCouples(vector<int>& row) { 7 int rSize = row.size(); 8 int cnt = 0; 9 for(int i = 0; i < rSize; i += 2) { 10 if(!checkCouple(row[i], row[i ^ 1])) { 11 cnt++; 12 bool tempMark = false; 13 for(int j = i + 2; j < rSize; j++) { 14 if(checkCouple(row[i], row[j]) && checkCouple(row[i ^ 1], row[j ^ 1])) { 15 tempMark = true; 16 swap(row[i ^ 1], row[j]); 17 break; 18 } 19 if(checkCouple(row[i ^ 1], row[j]) && checkCouple(row[i], row[j ^ 1])) { 20 tempMark = true; 21 swap(row[i], row[j]); 22 break; 23 } 24 } 25 if(tempMark) { 26 continue; 27 } 28 for(int j = i + 2; j < rSize; j++) { 29 if(checkCouple(row[i], row[j])) { 30 swap(row[i ^ 1], row[j]); 31 break; 32 } 33 if(checkCouple(row[i ^ 1], row[j])) { 34 swap(row[i], row[j]); 35 break; 36 } 37 } 38 } 39 } 40 return cnt; 41 } 42 };