本期,我给大家带来以下两个题目的讲解:
- 1、《华为机试》——MP3光标位置 (中等)
- 2、 2017年校招真题——洗牌 (简单)
以上两个题的难度属于我也给大家标注出来了,接下来,我们一起去分析一波这两个题!
1、MP3光标位置
我们先来研究一下第一个题,首先,我们还是先从题干下手进行理解:
题目如下 :👇
输入描述:
- 1 输入歌曲数量
- 2 输入命令 U或者D
输出描述:
- 1 输出当前列表
- 2 输出当前选中歌曲
示例1
输入: 10 UUUU 输出: 7 8 9 10 7
🤜 题意分析 🤛
第一眼看到这个题,可能会觉得这个一定非常复杂,其实不然,大家通过对题干的解读,我们可以发现其实本题的意思很简单。相信大家应该都使用过mp3的或者原来那个按键手机,有了上述的生活常识理解起来就非常简单。就是对其进行分类讨论,然后针对每种不同的情况进行解析即可!!
我们示例给大家分析一波:
- 初始时:
- 第一步:
- 第二步:
- 第三步:
- 第四步:
结束操作之后,此时我们还是处于当前页,因此此时first为7,所经历过的有 7,8,9,10 位置,因此最终的输出结果即为我们上述演示的这样。
🤜 解题思路 🤛
本题比较简单,通过解析指令,进行移动即可,分两种情况,歌曲数目不大于4和大于4的情况。
🤜 代码展示 🤛
#include <iostream> #include<string> using namespace std; int main() { int n; string cmd; while (cin >> n >> cmd) { //将n首歌进行编号1:n,其中num代表当前光标所在的歌曲编号,first代表当前页的第一首歌曲的编号 int num = 1, first = 1; if (n <= 4) { //歌曲总数<=4 for (int i = 0; i < cmd.size(); ++i) { //解析命令 if (num == 1 && cmd[i] == 'U') num = n; else if (num == n && cmd[i] == 'D') num = 1; else if (cmd[i] == 'U') num--; else num++; } for (int i = 1; i <= n; ++i) cout << i << " "; cout << endl; cout << num << endl; } else { //歌曲总数>4 for (int i = 0; i < cmd.size(); ++i) { //解析命令 if (first == 1 && num == 1 && cmd[i] == 'U') { first = n - 3; //将first跳入最后一页 num = n; } else if (first == n - 3 && num == n && cmd[i] == 'D') { first = num = 1; } else if (first != 1 && num == first && cmd[i] == 'U') { first--; num--; } else if (first != n - 3 && num == first + 3 && cmd[i] == 'D') { first++; num++; } else if (cmd[i] == 'U') num--; else num++; } for (int i = first; i <= first + 3; ++i) cout << i << " "; cout << endl; cout << num << endl; } } return 0; }
2、洗牌
紧接着研究一下第二个题,首先,我们还是先从题干下手进行理解:
题目如下 :👇
示例1
3 3 1 1 2 3 4 5 6 3 2 1 2 3 4 5 6 2 2 1 1 1 1
🤜 题意分析 🤛
本题的意思是第一行输入歌曲数量,第二行输入指令,最后需要显式的输出也为两行,第一行为当前歌曲所在的列表,第二行为光标所指向的歌曲。
- 初始时:
就开始移动 j 的下标,此时根据相应的公式我们可以得出洗一次牌之后第一个元素所处的位置,最后根据公式即可得出第一次洗完牌之后各元素所处的位置
🤜 解题思路 🤛
- 每次读取一个数之后,算出他经过k次洗牌后的位置,只用一个长度为2n数组用来输出
- 根据当前数的位置,可以算出经过一次洗牌后的位置
- 如果当前数小于等于n(即在左手),则他下次出现的位置是 2*当前位置
- 与之对应的当前位置 + n(即在右手)的牌,则他下次出现的位置是 2*当前位置 + 1
🤜 代码展示 🤛
#include <iostream> #include<vector> using namespace std; int main() { int n, m, k; cin >> n; while (n--) { cin >> m >> k; int num = 2 * m; vector<int> arr(num); for (int i = 0; i < num; ++i) { cin >> arr[i]; } //开始洗牌 for (int i = 0; i < k; ++i) { vector<int>tmp(arr.begin(), arr.end()); for (int j = 0; j < m; ++j) { arr[2 * j] = tmp[j]; //左手的牌排放的位置 arr[2 * j + 1] = tmp[j + m];//右手的牌排放的位置 } } //输出洗牌的顺序 for (int i = 0; i < num - 1; ++i) cout << arr[i] << " "; cout << arr[num - 1] << endl; //最后一张牌后面不能有空格 } } // 64 位输出请用 printf("%lld")
到此,本期的题目讲解便到此结束了!!!