記錄一下在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;
}
};