Leetcode滑动窗口题笔记

记录一下在leetcode上刷的滑动窗口的几道题,方便后边复习。
解析都放在代码里注释。

leetcode 15:

/*
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum


*/

/*
用排序加双指针,这个题主要是去重
*/
#include<iostream>
#include<vector>
#include<algorithm>
using std::cout;
using std::cin;
using std::vector;
using std::endl;
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        auto n = nums.size();
        vector<vector<int>> res;
        if (n < 3)
        {
            return {};
        }
        
        std::sort(nums.begin(),nums.end());  //先排序

        for (int i = 0; i < n - 2; i++)
        {
            if (nums[i] > 0)
            {
                break;
            }
            if (i > 0 && nums[i - 1] == nums[i])
            {
                continue;
            }
            int L = i + 1;          //两个指针一个指左边一个右边
            int R = n - 1;
            while (L < R)
            {
                if (nums[i] + nums[L] + nums[R] == 0)
                {
                    res.push_back({ nums[i],nums[L],nums[R] });
                    while (nums[L + 1] == nums[L] && L < R)
                    {
                        L = L + 1;
                    }
                    while (nums[R - 1] == nums[R] && L < R)
                    {
                        R = R - 1;
                    }
                    L = L + 1;
                    R = R - 1;
                }
                else if(nums[i] + nums[L] + nums[R] > 0)  //大于0的话就要减少 让右边的减小
                {
                    R = R - 1;
                }
                else
                {
                    L = L + 1;
                }

                
            }

        }
        return res;


    }
};

leetcode 1423:

/*
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

 

示例 1:

输入:cardPoints = [1,2,3,4,5,6,1], k = 3
输出:12
解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/

#include<iostream>
#include<vector>

using namespace std;

class Solution {
public:
    int maxScore(vector<int>& cardPoints, int k) {
        int n = cardPoints.size();
        int max = 0;
        //如果k要是大于等于n的话 就全加起来
        if (k >= n)
        {
            for (int i = 0; i < n; i++)
            {
                max = max + cardPoints[i];
            }
            return max;
        }
        int ans;
        int sum=0;
        vector<int> vec(k,0);
        //初始化滑动窗口
        for (int i = 0; i < k; i++)
        {
            vec[i] = cardPoints[i];
            sum = sum + cardPoints[i];
        }
        ans = sum;
    
        //依次滑动
        for (int i = 1; i <= k; i++)
        {
            sum = sum + (cardPoints[n - i] -vec[k-i]);
            if (sum > ans)
            {
                ans = sum;
            }
  
        }
        return ans;

    }
};

leetcode 1052:

/*
今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。

在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。

书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。

请你返回这一天营业下来,最多有多少客户能够感到满意的数量。
 

示例:

输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
输出:16
解释:
书店老板在最后 3 分钟保持冷静。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

*/
#include<iostream>
#include<vector>
#include<deque>
using namespace std;

class Solution {
public:
    int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int X) {
        int n = customers.size();
        int i;
        int ans=0;
        for (i = 0; i < n; i++)
        {
            if (grumpy[i] == 0)
            {
                ans = ans + customers[i];
            }
        }
        //发动技能的时候滑动窗口,窗口里面放下标
        
        deque<int> vec(X,0);
        for (i = 0; i < X; i++)
        {
            vec[i] =i;
            if (grumpy[i] == 1)
            {
                ans = ans + customers[i];
            }
        }
        int max = ans;
        for (int k = 1; k < n - X + 1; k++)
        {
            if (grumpy[vec[0]] == 1)
            {
                max = max - customers[vec[0]];
            }
            vec.pop_front();
            vec.push_back(X+k-1);
            if (grumpy[X + k - 1] == 1)
            {
                max = max + customers[X + k - 1];
            }
            if (max > ans)
            {
                ans = max;
           
            }

        }
        return ans;

    }
};

leetcode 295:

/*
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
*/
/*
解析:
用两个堆,最大堆和最小堆,最大堆让小的数字一半在最大堆,最小堆让大数字的一半去最小堆。
因为最大堆是从大到小,最小堆是从小到大,所以呢,中位数就是堆顶。所以要做的就是平衡两个堆的数目
如果k是奇数 k = 2*n+1 则允许最大堆持有n+1个元素 
当k 是偶数的时候,则两个堆都是n
*/
#include<iostream>
#include<queue>
#include<vector>
using namespace std;

class MedianFinder {
    priority_queue<int> lo;                              // 最大堆
    priority_queue<int, vector<int>, greater<int>> hi;   // 最小堆

public:
    
    void addNum(int num)
    {
        lo.push(num);                                    

        hi.push(lo.top());                               // 平衡
        lo.pop();

        if (lo.size() < hi.size()) {                     
            lo.push(hi.top());
            hi.pop();
        }
    }

    // 返回中值
    double findMedian()
    {
        return lo.size() > hi.size() ? (double)lo.top() : (lo.top() + hi.top()) * 0.5;
    }
};

leetcode 480:

/*
中位数是有序序列最中间的那个数。如果序列的大小是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

[2,3,4],中位数是 3
[2,3],中位数是 (2 + 3) / 2 = 2.5
给你一个数组 nums,有一个大小为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

 

示例:

给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。

窗口位置                      中位数            //排序的中位数  所以啊 理解错了

---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7      -1
 1  3 [-1  -3  5] 3  6  7      -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6
 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。

*/
/*
在295的基础上加些东西,也是用两个堆,但是加一个哈希表,里面添加那些被移出去的元素
一旦这些被移除去的元素在堆顶,那么就在堆顶删除(不是堆顶不好删除,所以等到在堆顶)
在删除,因为在堆里也不影响找中位数,还是堆顶那个。
但是注意保持平衡的时候,要算有效的数字,那么被移出窗口但是还没有从堆里删除的元素不能算进去
*/
#include<iostream>
#include<vector>
#include<deque>
#include<queue>
#include<unordered_map>
using namespace std;

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        vector<double> res;
        double ans;
        unordered_map<int, int> hash_table; //哈希表保存被移出窗口的元素
        priority_queue<int> max; //最大堆,里面保存小的那一半的数字
        priority_queue<int, vector<int>, greater<int>> min; //最小堆,里面保存大的那一半的元素

        int i = 0;
        int out_num, in_num, balance;

        //初始化两个堆
        while (i < k)
        {
            max.push(nums[i]);
            i++;
        }
        for (int j = 0; j < k / 2; j++)
        {
            min.push(max.top());
            max.pop();
        }

        while (1)
        {
            if (k % 2 == 0)  //如果k是偶数
            {
                ans = ((double)max.top() + (double)min.top()) / 2;
            }
            else
            {
                ans = max.top();   //因为我们是允许max里比min里多一个的
            }
            res.push_back(ans);
            if (i >= n)   //证明窗口滑完了
            {
                break;
            }
            
            out_num = nums[i-k]; //要被移出去的元素
            in_num = nums[i++];  //要进来的元素
            balance = 0;

            //如果那个要移出去的元素是max里面的,那么balance就-1,反之+1
            //因为我们规定max里面的元素比min里面的少 balance<0
            balance += (out_num <= max.top() ? -1 : 1);
            //移出去的元素放进哈希表里
            hash_table[out_num]++;

            //有出就有进
            if (!max.empty() && in_num <= max.top())  //比max.top()小 那就是进入max里
            {
                balance++;
                max.push(in_num);
            }
            else
            {
                balance--;
                min.push(in_num);
            }
            //看是不是还平衡
            if (balance < 0)   //max里面可用的元素少
            {
                max.push(min.top());
                min.pop();
                balance++;
            }
            if (balance > 0)
            {
                min.push(max.top());
                max.pop();
                balance--;
            }

            //如果堆顶元素是被移出去的,要清理
            while (hash_table[max.top()])
            {
                hash_table[max.top()]--;
                max.pop();
            }
            while (!min.empty() && hash_table[min.top()])
            {
                hash_table[min.top()]--;
                min.pop();
            }

        }
        return res;
    
        


    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章