算法思想一:哈希表

解题思路:

根据题意可知,三个人的位置为123,则排列方式有6中:123,132,213,231,312,321,因此只需要检查这六种预定结果需要变换多少次,取其最小值即可,使用到了哈希表记录每个数字出现的次数
检查每个预定结果需要多少次交换的时候,需要调用getmin函数,利用贪心思想,
1、首先看原数组与预定结果之间有多少位的差别
2、然后比较从每个预定结果的末尾位开始比较,若是相同则因为交换的时候跳过了,则交换次数加1,若是刚好等于预定结果的后一个数字,则交换次数减1,因为它的位置是正确的
3、最后更新最小的交换次数
图解:

代码展示:

JAVA版本
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param Position int整型一维数组 
     * @return int整型
     */
    public int ChangePosition (int[] Position) {
        // write code here
        // 哈希表统计每个数字出现的次数
        Map<Integer, Integer> map = new HashMap<>();
        map.put(1, 0);
        map.put(2, 0);
        map.put(3, 0);
        for (int i : Position) {
            map.put(i, map.get(i) + 1);
        }
        int[][] Lists = {{1, 2, 3}, {1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2}, {3, 2, 1}};
        int min = Integer.MAX_VALUE;
        for (int[] ints : Lists) {
            // 遍历每一种情况。找到最小值
            int s = getmin(Position, map, ints);
            min = Math.min(min, s);
        }
        return min;
    }
    private int getmin(int[] Position, Map<Integer, Integer> map, int[] L) {
        int k = 0, cnt = 0, Min = 0;
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < map.get(L[i]); j++){
                // 预定的位置不符合的数量
                if(Position[k] != L[i])
                    cnt++;
                k++;
            }
        }
        Min = cnt;
        // 每个数字预定模板中的结束下标
        int x = map.get(L[0]) - 1, y = x + map.get(L[1]), z = y + map.get(L[2]);
        for( ; x > 0; x--, y--, z--){
            // 每一位比较
            if(Position[x] == L[0])
                cnt++;
            else if(Position[x] == L[1])
                cnt--;
            if(Position[y] == L[1])
                cnt++;
            else if(Position[y] == L[2])
                cnt--;
            if(Position[z] == L[2])
                cnt++;
            else if(Position[z] == L[0])
                cnt--;
            Min = Math.min(Min, cnt);
        }
        return Min;
    }
}

复杂度分析

时间复杂度为数组长度,因为都是一次遍历
空间复杂度虽然借助哈希表和辅助数组,但是辅助数组Lists只有18个变量,哈希表只使用了3个空间

算法思想二:优化

解题思路:

因为题目说的这是一个循环,因此123和132两个预定结果就可以代替所有六种:
123 = 312 = 231
132 = 321 = 213
因此可以对方法一优化成只有两种情况,再类似比较两种情况的较小值。因为要用循环来比较,因此比较的时候下标需要取模运算。

代码展示:

Python版本
class Solution:
    def ChangePosition(self , Position ):
        # write code here
        n = len(Position)
        # 统计每个数字出现的次数
        count_1 = 0
        count_2 = 0
        count_3 = 0
        for p in Position:
            if p == 1:
                count_1+=1
            elif p == 2:
                count_2+=1
            else:
                count_3+=1
        window_123 = 0
        window_132 = 0
        for i, p in enumerate(Position):
            # 统计与两个预定结果不同位置数
            if i < count_1:
                if not p == 1:
                    window_123+=1
                    window_132+=1
            else:
                if count_1 <= i < count_1+count_2:
                    if not p == 2:
                        window_123+=1
                else:
                    if not p == 3:
                        window_123+=1
                if count_1 <= i < count_1+count_3:
                    if not p == 3:
                        window_132+=1
                else:
                    if not p == 2:
                        window_132+=1
        result = min(window_123,window_132)
        # 遍历和方法一样。开始一一调换
        for i in range(1,n):
            if Position[(i-1)%n] == 1:
                window_123+=1
                window_132+=1
            if Position[(count_1-1+i)%n] == 1:
                window_123-=1
                window_132-=1
            if Position[(count_1-1+i)%n] == 2:
                window_123+=1
            if Position[(count_1+count_2-1+i)%n] == 2:
                window_123-=1
            if Position[(count_1-1+i)%n] == 3:
                window_132+=1
            if Position[(count_1+count_3-1+i)%n] == 3:
                window_132-=1
            if Position[(count_1+count_2-1+i)%n] == 3:
                window_123+=1
            if Position[(count_1+count_2+count_3-1+i)%n] == 3:
                window_123-=1
            if Position[(count_1+count_3-1+i)%n] == 2:
                window_132+=1
            if Position[(count_1+count_2+count_3-1+i)%n] == 2:
                window_132-=1
            result = min(result, window_132, window_123)
        return result

复杂度分析

时间复杂度为数组长度,三次单层遍历
空间复杂度:仅使用常数级空间