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


时间复杂度:
空间复杂度: