一、询问学号
题⽬来源:洛⾕
题⽬链接:P3156 【深基15.例1】询问学号 - 洛谷
难度系数:★
1. 题目描述
2. 算法原理
直接⽤ vector 或者数组模拟即可。
3. 参考代码
#include <iostream>
#include <vector>using namespace std;const int N = 2e6 + 10;int n, m;
vector<int> a(N);int main()
{cin >> n >> m;for(int i = 1; i <= n; i++) cin >> a[i];while(m--){int x; cin >> x;cout << a[x] << endl;}return 0;
}
二、寄包柜
题⽬来源:洛⾕
题⽬链接:P3613 【深基15.例2】寄包柜 - 洛谷
难度系数:★
1. 题目描述
2. 算法原理
解法1:创建二维数组(空间复杂度过高)
解法2:使用vector——vector<int> a[N]
注意:
vector<int> a[N]
定义了一个包含N
个vector<int>
对象的数组。(类似二维数组)vector<int> a(N)
定义了一个vector<int>
对象a
,并将其初始化为包含N
个元素,这些元素的初始值默认为 0(对于int
类型)。
3. 参考代码
#include <iostream>
#include <vector>using namespace std;const int N = 1e5 + 10;int n, q;
vector<int> a[N]; // 创建 N 个柜子int main()
{cin >> n >> q;while(q--){int op, i, j, k;cin >> op >> i >> j;if(op == 1) // 存{cin >> k;if(a[i].size() <= j){// 扩容a[i].resize(j + 1);}a[i][j] = k;}else // 查询{cout << a[i][j] << endl;}}return 0;
}
三、移动零
题⽬来源:⼒扣
题⽬链接:283. 移动零 - 力扣(LeetCode)
难度系数:★
1. 题目描述
2. 算法原理
利用双指针
类⽐数组分两块的算法思想,这⾥是将数组分成三块,那么我们可以再添加⼀个指针,实现数组分三 块。
设数组⼤⼩为 n ,定义三个指针 left, cur,right :
- left :⽤来标记 0 序列的末尾,因此初始化为 -1 ;
- cur⽤来扫描数组,初始化为 0 ;
- right :⽤来标记 2 序列的起始位置,因此初始化为 n 。
在往后扫描的过程中,保证:
- [0, left] 内的元素都是 0 ;
- [left + 1,cur − 1]内的元素都是 1 ;
- [cur, right − 1] 内的元素是待定元素;
- [right, n] 内的元素都是 2 。
3. 参考代码
class Solution
{
public:void moveZeroes(vector<int>& nums) {for(int i = 0, cur = -1; i < nums.size(); i++){if(nums[i]) // 非0元素{swap(nums[++cur], nums[i]);}}}
};
四、颜⾊分类
题⽬来源:⼒扣
题⽬链接:75. 颜色分类 - 力扣(LeetCode)
难度系数:★
1. 题目描述
2. 算法原理
类⽐数组分两块的算法思想,这⾥是将数组分成三块,那么我们可以再添加⼀个指针,实现数组分三 块。
设数组⼤⼩为 ,定义三个指针left, cur,right :
- left:⽤来标记 序列的末尾,因此初始化为 ;
- cur:⽤来扫描数组,初始化为 ;
- right:⽤来标记 序列的起始位置,因此初始化为 。
在 往后扫描的过程中,保证:
- [0, left] 内的元素都是 ;
- [left + 1,cur − 1] 内的元素都是 ;
- [cur, right − 1] 内的元素是待定元素;
- [right, n] 内的元素都是 。
3. 参考代码
class Solution
{
public:void sortColors(vector<int>& nums) {int left = -1, i = 0, right = nums.size();while(i < right){if(nums[i] == 0) swap(nums[++left], nums[i++]);else if(nums[i] == 1) i++;else swap(nums[--right], nums[i]);}}
};
五、合并两个有序数组
题⽬来源:⼒扣
题⽬链接:88. 合并两个有序数组 - 力扣(LeetCode)
难度系数:★
1. 题目描述
2. 算法原理
解法⼀:利⽤辅助数组(需要学会,归并排序的核⼼步骤)
可以创建⼀个辅助数组,然后⽤两个指针分别指向两个数组。每次拿出⼀个较⼩的元素放在辅助数组 中,直到把所有元素全部放在辅助数组中。最后把辅助数组的结果覆盖到 nums1 中。
解法⼆:原地修改(本题的最优解)
与解法⼀的核⼼思想是⼀样的。
由于第⼀个数组的空间本来就是 n+m 个,所以我们可以直接把最终结果放在 nums1 中。 nums1 中。为了不 覆盖未遍历到的元素,定义两个指针指向两个数组的末尾,从后往前扫描。每次拿出较⼤的元素也是 从后往前放在 nums1 的后⾯,直到把所有元素全部放在 nums1 中。
注意:从前往后遍历会出现覆盖的情况
3. 参考代码
//解法一
class Solution
{
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 解法一:利用辅助数组vector<int> tmp(m + n);int cur = 0, cur1 = 0, cur2 = 0;while(cur1 < m && cur2 < n){if(nums1[cur1] <= nums2[cur2]) tmp[cur++] = nums1[cur1++];else tmp[cur++] = nums2[cur2++];}while(cur1 < m) tmp[cur++] = nums1[cur1++];while(cur2 < n) tmp[cur++] = nums2[cur2++];for(int i = 0; i < n + m; i++) nums1[i] = tmp[i];}
};//解法二
class Solution
{
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 解法二:原地合并int cur1 = m - 1, cur2 = n - 1, cur = m + n - 1;while(cur1 >= 0 && cur2 >= 0){if(nums1[cur1] >= nums2[cur2]) nums1[cur--] = nums1[cur1--];else nums1[cur--] = nums2[cur2--];}while(cur2 >= 0) nums1[cur--] = nums2[cur2--];}
};
六、The Blocks Problem
题⽬来源:洛⾕
题⽬链接:UVA101 The Blocks Problem - 洛谷
难度系数:★★
2. 算法原理
本质是⼀个模拟题,可以⽤ vector 来模拟,注意细节问题。
3. 参考代码
#include <iostream>
#include <vector>using namespace std;const int N = 30;
typedef pair<int, int> PII;int n;
vector<int> p[N]; // 创建 n 个放木块的槽PII find(int x)
{for(int i = 0; i < n; i++){for(int j = 0; j < p[i].size(); j++){if(p[i][j] == x){return {i, j};}}}
}void clean(int x, int y)
{// 把 [x, y] 以上的木块归位for(int j = y + 1; j < p[x].size(); j++){int t = p[x][j];p[t].push_back(t);}p[x].resize(y + 1);
}void move(int x1, int y1, int x2)
{// 把 [x1, y1] 及其以上的木块放在 x2 上面for(int j = y1; j < p[x1].size(); j++){p[x2].push_back(p[x1][j]);}p[x1].resize(y1);
}int main()
{cin >> n;// 初始化for(int i = 0; i < n; i++){p[i].push_back(i);}string op1, op2;int a, b;while(cin >> op1 >> a >> op2 >> b){// 查找 a 和 b 的位置PII pa = find(a);int x1 = pa.first, y1 = pa.second;PII pb = find(b);int x2 = pb.first, y2 = pb.second;if(x1 == x2) continue; // 处理不合法的操作if(op1 == "move") // 把 a 上方归位{clean(x1, y1);}if(op2 == "onto") // 把 b 上方归位{clean(x2, y2);}move(x1, y1, x2);}// 打印for(int i = 0; i < n; i++){cout << i << ":";for(int j = 0; j < p[i].size(); j++){cout << " " << p[i][j];}cout << endl;}return 0;
}