算法思想一:遍历
解题思路:
可分为没插过队的和插过队的两种,最后的排队,没插过队的都在后面,插过队的最大值是个分界线。
没插过队的小于这个分界线最后一定不在原来的位置,大于的一定在原来位置,插过队的,我们从后往前看,删除重复的,就是排队序列
直接统计插过队的还在原来位置上的人数即可
代码展示:
Python版本
class Solution:
def countDislocation(self , n , cutIn ):
# write code here
# 哈希表
cd = set()
m = len(cutIn)
if m == 0:
return 0
# 插队的最大编号
res = max(cutIn)
# 倒序遍历
for i in range(m-1,-1,-1):
if cutIn[i] not in cd:
# 如果当前人插队编号等于已插队的人数+1,则其还会处于原来位置
if cutIn[i]==len(cd)+1:
# 去除还在原来位置的人
res-=1
# 记录已插队的人
cd.add(cutIn[i])
return res复杂度分析
时间复杂度:N表示插入数组的长度,遍历插队数组时间
空间复杂的:哈希表占用空间
算法思想二:逆向思维
解题思路:
先来看一个例子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的一定不在原来位置(结合生活实际,很好理解:我们在排队的时候,不太关心排在自己前面的人的位置变动,因为这不会影响到我们自己的等待时间,但是一旦排在自己后面的人插到自己前面,我们就会很不爽,因为这会造成自己的等待时间边长)
题目让求有多少个人已经不在原来队伍的位置,我们可以逆向思维计算有多少人还在原来的位置,然后减去这个值就能得到位置改变的总人数
下图展示了例子中队伍的判断情况:
代码展示:
JAVA版本
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算有多少个人最终不在自己原来的位置上
* @param n int整型 队伍总长
* @param cutIn int整型一维数组 依次会插队到最前方的人的编号
* @return int整型
*/
public int countDislocation (int n, int[] cutIn) {
// write code here
// 特殊情况
if(cutIn.length == 0) return 0;
// 初始化
HashMap 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 记录遍历过的数字
visited.put(cutIn[i], true);
// 判断插入人数恰好是该人原位置,则 same++
if(cutIn[i] == number++) same++;
// 插队中找到最大的数,该数之前的位置都会变化,之后的都不会变化
max = Math.max(max, cutIn[i]);
}
}
return max - same;
}
}复杂度分析
时间复杂度:N表示插入数组的长度,遍历插队数组时间
空间复杂的:哈希表占用空间



京公网安备 11010502036488号