算法笔试准备

image

image

双指针, 一样的题,就是把数字换成字符。

思路就是遍历数组a中的每一个元素a[i], 对于每一个i,找到j使得双指针[j, i]维护的是以a[i]结尾的最长连续不重复子序列,长度为i - j + 1, 将这一长度与res的较大者更新给res。
而对于每一个i,因为[j, i - 1]是前一步得到的最长连续不重复子序列,所以如果[j, i]中有重复元素,一定是a[i]和[j, i - 1]之间的一个数重复了,因此就右移j直到a[i]不重复为止。

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

int n;
int a[N], cnt[N];


int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    
    int res = 0, j = 0;
    for (int i = 0; i < n; i ++ )
    {
        cnt[a[i]] ++ ;
        while (cnt[a[i]] > 1 && j < i)
        {
            cnt[a[j]] -- ;
            j ++ ;
        }
        res = max(res, i - j + 1);
    }
    cout << res << endl;
    
    return 0;
}

image

找规律:接满雨水之后,数组在最大值左边不严格递增,右边不严格递减。

比如样例接满雨水之前是:0 1 0 2 1 0 1 3 2 1 2 1

那么接满雨水之后就是:   0 1 1 2 2 2 2 3 2 2 2 1
因此只需要把原数组变成符合这样要求的数组就行了,改变的量就是接的雨水。
具体实现只需要先找到整体的最大值下标,左右各自遍历一遍
两边都维护一个值来表示之前的最大值以保证单调性,
如果比最大值小,说明有坑可以积雨,雨水量就加上这个差值,
如果大于等于,就说明没坑没法积雨,就更新最大值。

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

int n;
int a[N];

int main()
{
    cin >> n;
    int mx = 0, idx = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        if (mx < a[i])
        {
            mx = a[i];
            idx = i;
        }
    }
    
    int res = 0;
    int cur = a[1];
    for (int l = 1; l <= idx; l ++ )
    {
        if (a[l] > cur) cur = a[l];
        else res += cur - a[l];
    }
    cur = a[n];
    for (int r = n; r >= idx; r -- )
    {
        if (a[r] > cur) cur = a[r];
        else res += cur - a[r];
    }
    
    cout << res << endl;
    
    return 0;
}

 

 

 

 

image

 双指针+贪心,

题目中的示例为:

[1, 8, 6, 2, 5, 4, 8, 3, 7]
在初始时,左右指针分别指向数组的左右两端1和7,它们可以容纳的水量为 min(height[1],height[7])∗8=8。

此时我们需要移动一个指针。移动哪一个呢?直觉告诉我们,应该移动对应数字较小的那个指针(即此时的左指针)。这是因为,由于容纳的水量是由两个指针指向的数字中较小值∗指针之间的距离

决定的。如果我们移动数字较大的那个指针,那么前者「两个指针指向的数字中较小值」不会增加,后者「指针之间的距离」会减小,那么这个乘积会减小。因此,我们移动数字较大的那个指针是不合理的。因此,我们移动 数字较小的那个指针。

所以,我们将左指针向右移动:

此时可以容纳的水量为 min(8,7)∗7=49。由于右指针对应的数字较小,我们移动右指针

此时可以容纳的水量为 min(8,3)∗6=18。由于右指针对应的数字较小,我们移动右指针

此时可以容纳的水量为 min(8,8)∗5=40。两指针对应的数字相同,我们可以任意移动一个,例如移动左指针

此时可以容纳的水量为 min(6,8)∗4=24。由于左指针对应的数字较小,我们移动左指针,并且可以发现,在这之后左指针对应的数字总是较小,因此我们会一直移动左指针,直到两个指针重合。在这期间,对应的可以容纳的水量为:min(2,8)∗3=6,min(5,8)∗2=10,min(4,8)∗1=4。

在我们移动指针的过程中,计算到的最多可以容纳的数量为 49,即为最终的答案。

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

int n;
int a[N];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    
    int l = 1, r = n;
    int res = 0;
    while (l < r)
    {
        res = max(res, (r - l) * min(a[l], a[r]));
        if (a[l] < a[r]) l ++ ;
        else r -- ;
    }
    cout << res << endl;
    
    return 0;
}

image

 

image

 

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>>res;
        int len = nums.size();
        sort(nums.begin(), nums.end());
        for (int i = 0; i < len; i ++ )
        {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue;

            int l = i + 1, r = len - 1;
            while (l < r)
            {
                if (nums[i] + nums[l] + nums[r] == 0) 
                {
                    res.push_back(vector<int>{nums[i], nums[l], nums[r]});
                    l ++ , r -- ;
                    while(l < r && nums[l] == nums[l - 1]) l ++ ;
                    while(l < r && nums[r] == nums[r + 1]) r -- ;
                }
                else if (nums[i] + nums[l] + nums[r] < 0)
                {
                    l ++ ;
                    while (l < r && nums[l] == nums[l - 1]) l ++ ;
                }
                else 
                {
                    r -- ;
                    while (l < r && nums[r] == nums[r + 1]) r -- ;
                }
            }
        }
        return res;
    }
};

image

 滑动窗口,由于是从前往后加,所以当某次sum大于目标值的时候,从前面开始减就可以

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, res = 0x3f3f3f3f;
        int j = 0;
        for (int i = 0; i < nums.size(); i ++ )
        {
            sum += nums[i];
            while(sum >= target) 
            {
                res = min(res, i - j + 1);
                sum -= nums[j];
                j ++ ;
            }
        }
        if (res == 0x3f3f3f3f) return 0;
        else return res;
    }
};

image

 单调队列,不想做了,直接滑动窗口打个暴力算了

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int>res;
        for (int i = 0; i <= nums.size() - k; i ++ ) 
        {
            int mx = -0x3f3f3f3f;
            for (int j = i; j <= i + k - 1; j ++ )
            {
                mx = max(mx, nums[j]);
            }
            res.push_back(mx);
        }
        return res;
    }
};

 

posted @ 2026-08-14 01:37  彦辰kkkkk  阅读(2)  评论(0)    收藏  举报