[牛客题霸-高频算法面试题]那些插队的人

题目描述

你有一个长度为 n 的队伍,从左到右依次为 1~n,有 m 次插队行为,用数组 cutIn 进行表示,cutIn 的元素依次代表想要插队的人的编号,每次插队,这个人都会直接移动到队伍的最前方。你需要返回一个整数,代表这 m 次插队行为之后,有多少个人已经不在原来队伍的位置了。

示例1

输入:3,[3, 2, 3]

输出:2

说明:

初始队伍为 [1, 2, 3]

3 开始插队 [3, 1, 2]

2 开始插队 [2, 3, 1]

3 开始插队 [3, 2, 1]

所以2还在原来的尾置,3和1两个人已经不在原来的位置了。

 

思路

先来看一个例子15 [10, 4, 6, 5, 9, 7, 3, 3, 9, 10],我们来模拟一下插队过程。

第一次:10

第二次:4 10

第三次:6 4 10

第四次:5 6 4 10

第五次:9 5 6 4 10

第六次:7 9 5 6 4 10

第七次:3 7 9 5 6 4 10

第八次:3 7 9 5 6 4 10

第九次:9 3 7 5 6 4 10

第十次:10 9 3 7 5 6 4

最终位置:10 9 3 7 5 6 4 1 2 8 11 12 13 14 15

可以发现,队伍最终的排列是由最后一次插队决定的,然后没插队的人全部依次排在插队的人的后面。因此从后往前遍历cutIn数组,遇到重复的跳过。

判断是否还在原位置时,将队伍分为两部分计算:插队的人和没插队的人。对于插队的人,直接判断位置和序号是否匹配;设插队的人中最大序号为max,对于没插队的人,序号>max的一定还在原来队伍中的位置,<max的一定不在原来位置(结合生活实际,很好理解:我们在排队的时候,不太关心排在自己前面的人的位置变动,因为这不会影响到我们自己的等待时间,但是一旦排在自己后面的人插到自己前面,我们就会很不爽,因为这会造成自己的等待时间边长)

题目让求有多少个人已经不在原来队伍的位置,我们可以逆向思维计算有多少人还在原来的位置,然后减去这个值就能得到位置改变的总人数。

下图展示了例子中队伍的判断情况:

tips:

Set、HashMap等数据结构都可以处理重复值。HashMap的key值是编号这个没问题,对于value类型的选择,我直接用true/false来记录是否访问过;也可以使用Integer来记录编号为key的人在队伍中的最终位置。其实仔细观察会发现我们全程并不关心value值是多少(我们是通过map.containsKey()来判断是否重复的),也就是说HashMap完全可以退化成Set,不过实际提交代码时发现使用HashMap的程序运行时间更短,所以下面的代码还是用HashMap了。

JAVA代码

public class Solution {
    /**
     * 计算有多少个人最终不在自己原来的位置上
     * @param n int整型 队伍总长
     * @param cutIn int整型一维数组 依次会插队到最前方的人的编号
     * @return int整型
     */
    public int countDislocation (int n, int[] cutIn) {
        if(cutIn.length == 0) return 0;
        HashMap<Integer, Boolean> visited = new HashMap<>();
        int max = 0, same = 0, number = 1;
        for(int i = cutIn.length - 1; i >= 0; i--) {
            if(!visited.containsKey(cutIn[i])) {
                visited.put(cutIn[i], true);
                if(cutIn[i] == number++) same++;
                max = Math.max(max, cutIn[i]);
            }
        }
        return max - same;
    }
}
posted @ 2020-05-08 19:56  夭夭夭夭夭桃子  阅读(430)  评论(0编辑  收藏  举报