NO.44十六届蓝桥杯备战|顺序表习题|询问学号|寄包柜|移动零|颜色分类|合并两个有序数组|pair(C++)

发布于:2025-03-18 ⋅ 阅读:(17) ⋅ 点赞:(0)
P3156 【深基15.例1】询问学号 - 洛谷

直接⽤ vector 或者数组模拟即可

#include <bits/stdc++.h>
using namespace std;

const int N = 2e6 + 10;
int n, m;
vector<int> a(N);

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    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 0 5 × 1 0 5 10^{5}\times 10^5 105×105⼤⼩的数组,空间会超。但是格⼦的总数量是 1 0 7 10^7 107 ,⽤数组模拟是完全够⽤的。因此可以⽤动态扩容的数组,创建 1 0 5 10^5 105个vector来模拟

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
vector<int> a[N];
int n, q;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    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)

在本题中,我们可以⽤⼀个cur指针来扫描整个数组,另⼀个dest指针⽤来记录⾮零数序列的最后⼀个位置。根据cur在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
在cur遍历期间,使[0, dest]的元素全部都是⾮零元素,[dest + 1, cur - 1]的元素全是零
cur:扫描数组
分类讨论:

  1. 遇到0,直接cur++
  2. 遇到非0,swap(dest+1,cur),dest++,cur++
    ![[Pasted image 20250316191801.png]]

一开始dest=-1,cur=0
cur指向0,cur直接++
![[Pasted image 20250316191955.png]]

cur指向1,交换dest+1和cur,dest+1是0元素区间的第一个位置,cur是当前遍历的元素,cur+1是待遍历的区间
![[Pasted image 20250316192924.png]]

然后dest++,cur++
![[Pasted image 20250316193405.png]]

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for (int cur = 0, dest = -1; cur < nums.size(); cur++)
        {
            if (nums[cur])
            {
                swap(nums[++dest], nums[cur]);
            }
        }
    }
};
75. 颜色分类 - 力扣(LeetCode)
class Solution {
public:
    void sortColors(vector<int>& nums) {
        sort(nums.begin(), nums.end());
    }
};

定义三个指针
cur:扫描数组
left:标记的是0区间的最后一个元素
right:标记的是2区间的第一个元素

在cur 往后扫描的过程中,保证:

  • [0, lef t]内的元素都是0 ;
  • [lef t + 1, cur - 1] 内的元素都是1 ;
  • [cur, right - 1] 内的元素是待定元素;
  • [right, n]内的元素都是2 。
    ![[Pasted image 20250316203936.png]]

cur指向2,让right-1位置的元素和cur指向的元素交换,再right–
因为此时的cur是待扫描的数,所以cur不能动
![[Pasted image 20250316210022.png]]

此时cur碰到0,让left+1和cur的位置交换,left++,cur++
![[Pasted image 20250316210139.png]]

cur碰到2,与right-1位置交换,right–
![[Pasted image 20250316210226.png]]

当cur碰到1,cur++
![[Pasted image 20250316210544.png]]

直到cur与right相遇,遍历结束

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int left = -1, cur = 0, right = nums.size();
        while (cur < right)
        {
            if (nums[cur] == 0) swap(nums[++left], nums[cur++]);
            else if(nums[cur] == 1) cur++;
            else swap(nums[--right], nums[cur]);
        }
    }
};
88. 合并两个有序数组 - 力扣(LeetCode)

辅助数组
可以创建⼀个辅助数组,然后⽤两个指针分别指向两个数组。每次拿出⼀个较⼩的元素放在辅助数组中,直到把所有元素全部放在辅助数组中。最后把辅助数组的结果覆盖到nums1中

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];
    }
};

原地合并,需要反着遍历
cur1定义为整个nums1数组最大的值,cur2定义为整个nums2数组最大的值,cur指向的是整个nums1数组m+n的最后一个元素的位置

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int cur1 = m - 1, cur2 = n - 1, cur = n + m - 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--];
    }
};
pair

pair是C++标准库中的一个模板类,用于将两个值组合成一个单一的对象,通常用于存储键值对或返回多个值,有两个公有成员first和second,分别表示第一个值和第二个值

struct pair
{
	type first;
	type second;
};

使用的时候可以指定first和second的类型
指定的方式为pair<第一个关键字的类型,第二个关键字的类型>

pair<int, int> p1;
pair<long long, int> p2;
pair<string, int> p3;

不过,一般使用pair的时候,一般会typedef一下

typedef pair<int, int> PII;
PII p1;

typedef pair<long long, long long> PLL;
PLL p2;
UVA101 The Blocks Problem - 洛谷

move:a上方归位
pile:a及a上放在b上
onto:b上方归位,a及a上放在b上
over:a及a上放在b上
总结为2种操作:归位;移动

#include <bits/stdc++.h>
using namespace std;

const int N = 30;
typedef pair<int, int> PII;
int n;
vector<int> p[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)
{
    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)
{
    for (int j = y1; j < p[x1].size(); j++)
    {
        p[x2].push_back(p[x1][j]);        
    }
    p[x1].resize(y1);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    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")
        {
            clean(x1, y1);
        }
        if (op2 == "onto")
        {
            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;
}

网站公告

今日签到

点亮在社区的每一天
去签到