题意:
有三种不同的值,分别为1,2,3。
每种值有若干个,先要将相同的值靠在一起。(注意:首尾是相连的)
请问需要交换最少多少个数。
方法一:
暴力模拟
思路:
三种值的排列为
模拟每一种排列方式。
-----------------------------------------------------------------------------------------------------
核心思想:因为是三种数,所以划分为三个区间。又根据不同值的个数,所以可知三个区间分别的范围。
然后每次每个区间向左平移一个单元,取暴力遍历,维护最小值答案。
----------------------------------------------------------------------------------------------------------
操作:假设序列为{1,2,3}.
首先初始操作查看原数组与序列的不同,并计数num;
之后便得到1,1,1。。。2,2,2。。。3,3,3,3,3。。。这样相同值相邻的序列。
接着,从每一个区间的末尾开始向左遍历。如果等于当前值,说明之前初始操作没计过数,现在要变成右边的数,所以num++;如果等于下一个数,即之前初始操作是计过数的,所以num--。
维护最小值res.
class Solution { public: map<int,int> cnt;//计数数组 int a[6][3]= {{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}};//不同排列 int res=1e5+5; int ChangePosition(vector<int>& Position) { int n=Position.size(); for(int i=0; i<n; i++){//计数 cnt[Position[i]]++; } for(int i=0; i<6; i++){//不同排列 int num=0;//换位置的人数 int l=0; for(int j=0; j<3; j++){ for(int k=0; k<cnt[a[i][j]]; k++,l++){ if(Position[l]!=a[i][j])//不相同,num++ num++; } } res=min(res,num);//维护最小值 int x=cnt[a[i][0]]-1,y=x+cnt[a[i][1]],z=y+cnt[a[i][2]]; while(x){ if(Position[x]==a[i][0])//等于自己,要变成下个数,所以num++ num++; else if(Position[x]==a[i][1])//等于下个数,又因为之前统计过这个数,之前num--了,要恢复,所以num-- num--; if(Position[y]==a[i][1]) num++; else if(Position[y]==a[i][2]) num--; if(Position[z]==a[i][2]) num++; else if(Position[z]==a[i][0]) num--; res=min(res,num);//维护最小值 x--; y--; z--; } } return res; } };
时间复杂度:空间复杂度:
方法二
模拟+优化
思路:根据方法一的思路,可知我们都是循环向左平移的。
又因为{1,2,3},{2,3,1},{3,1,2}这三者等效,和 {1,3,2},{3,2,1},{2,1,3}这三者等效。因此,向左平移的次数就可以确认是(长度-1)。
class Solution { public: map<int,int> cnt;//计数数组 int a[2][3]= {{1,2,3},{1,3,2}};//不同排列 int res=1e5+5; int ChangePosition(vector<int>& Position) { int n=Position.size(); for(int i=0; i<n; i++){//计数 cnt[Position[i]]++; } for(int i=0; i<2; i++){//不同排列 int num=0;//换位置的人数 int l=0; for(int j=0; j<3; j++){ for(int k=0; k<cnt[a[i][j]]; k++,l++){ if(Position[l]!=a[i][j])//不相同,num++ num++; } } res=min(res,num);//维护最小值 int x=cnt[a[i][0]]-1,y=x+cnt[a[i][1]],z=y+cnt[a[i][2]]; int m=n-1; while(m--){//循环左移,执行n-1次 if(Position[x]==a[i][0])//等于自己,要变成下个数,所以num++ num++; else if(Position[x]==a[i][1])//等于下个数,又因为之前统计过这个数,之前num--了,要恢复,所以num-- num--; if(Position[y]==a[i][1]) num++; else if(Position[y]==a[i][2]) num--; if(Position[z]==a[i][2]) num++; else if(Position[z]==a[i][0]) num--; res=min(res,num);//维护最小值 x=(x-1+n)%n;//左移 y=(y-1+n)%n; z=(z-1+n)%n; } } return res; } };
时间复杂度:
空间复杂度: