题目:那些插队的人
描述:你有一个长度为 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两个人已经不在原来的位置了。
解法一:
思路分析:这道题应该属于一道非常有趣的数学问题,在此说明,礼貌排队,不要插队,在长度为n的队伍中,有m次插队的行为,插队者在数组中有编号,如果该编号想要插队的话就将该编号直接存放在数组的首位,然后依次循环,当插队结束,统计一下有多少人不在原先的位置即可,这就是本题的大意。
实例分析:输入:3,[3, 2, 3]
——由上述分析可以清晰的看到3和1的位置发生了改变,所以输出2
——我们根据上表进行分析,队伍在排列的过程中主要是由最后一次插队所决定的,没插队的人始终会排列在插队人的后面(没插队的人是最倒霉的)因此我们只需要遍历cutIn数组,当有重复的人就把他抛过,需要统计有多少人不在原位置,我们也可以统计有多少人在原位置,然后将总的人数减去在原位置的人数,最终得到的就是不在原位置的人数,因为有的人会插队,所以在排列的过程会有两种人需要进行计算,对于插队的人,需要判断当前位置是否与原序号相匹配,对于没插队的人,我们只要判断插队的人的最大序号,大于最大序号的人一定还在原来的队伍中,小于最大序号的人一定不在原序号中,所以据此分析即可完成相应的统计。
——首先我们设定三个值,表示插队的最大序号数,
表示还在原位置的人,
表示正常的序号。对cutIn数组进行遍历循环,存在没有插过队也就是false,就执行if语句,在if语句中,主要判断三个点,最大序号数,位置不变的,插过队的记为true,最后使用
就可以得到最终的结果。
举例说明:输入:7,[3,2,3,5,1]
代码执行过程:
正常分析过程:
结合上下表格,就能得出最终的结果。
C++核心代码为:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算有多少个人最终不在自己原来的位置上
* @param n int整型 队伍总长
* @param cutIn int整型vector 依次会插队到最前方的人的编号
* @return int整型
*/
int countDislocation(int n, vector<int>& cutIn) {
// write code here
int len = cutIn.size();//插队的人总数,含重复的
if(len == 0)//没有人插队,返回0
return 0;
int maxl = 0;
vector<bool> dp(n + 1, false);//初始化n个人,初始值false
int common = 0;
int count = 0;
for(int i = len - 1; i >= 0; i--){
if(!dp[cutIn[i]]){//没有插队的执行,重复插队的就不考虑了
maxl = max(maxl, cutIn[i]);
if(cutIn[i] == ++count)
//因为是从最后开始循环的,所以1 = 1类似的重合
common++;
dp[cutIn[i]] = true;//变了设为true
}
}
return maxl - common;
}
};上述代码有一个for循环用来循环数组的长度N,所以其时间复杂度为,设定了额外的内存空间dp用来存储访问过的插队人数,所以空间复杂度为
。
解法二:
思路分析:我们通过解法一发现,每一次插队的人的位置和其最后一次插队有关,就比如输入:7,[3,2,3,5,1],第一个3和第三个3,在顺序遍历的情况下第一个3没什么用,这也是为什么在解法一种不执行最后一步的原因,我们使用set和vector结合来解决,首先通过逆序遍历计算出前n个变的值的总数,通过对前n个数进行判断来求解。其中检测容器set1,用来存放第一次出现的数,存放容器res,用来存放所有人插完队后,插队人的容器。
C++核心代码为:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算有多少个人最终不在自己原来的位置上
* @param n int整型 队伍总长
* @param cutIn int整型vector 依次会插队到最前方的人的编号
* @return int整型
*/
int countDislocation(int n, vector<int>& cutIn) {
// write code here
if (cutIn.size() == 0 || n <= 1){
return 0;
}
unordered_set<int> s1;//用来存放第一次出现的数
vector<int> res;//存放容器
int max = 1;
int len = cutIn.size();
for(int i = len - 1;i >= 0;i--){
int index = cutIn[i];//index接收cutIn的值
if(s1.find(index) == s1.end())//没有找到
{
s1.insert(index);//在s1中添加该数
res.push_back(index);//将该数放入res容器中
max = index > max ? index : max;//记录最大值
}
}
int result = max;//记录不在原位置的值
for(int i=0;i<res.size();i++){//该数在原位置上,那么result减一
if(res[i] == i+1){
result--;
}
}
return result;
}
};——该算法首先需要循环找到最大序号值的元素,然后再循环判断序号值与值是否相同,所以其时间复杂度还是,空间复杂度借助了一个set容器和vector容器,所以空间复杂度为
。
解法三:
思路分析:也可以使用暴力法进行分析,首先给定一个容器v1记录1 - n的容器,且赋予初始值false,还需要给定一个容器v2复制一份v1的值用来跟对比后的v1进行比较记录,然后进行逐个遍历最终确定变了序号的人的数量,该方法循环次数多,且占用内存空间大,所以就不进行代码展示。

京公网安备 11010502036488号