题意:
有三种不同的值,分别为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;
}
}; 时间复杂度:
空间复杂度:



京公网安备 11010502036488号