239. 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 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 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1 输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
解题思路:
1.
队列里面的数递减的顺序。2.如果前面的数小于新的数,就弹出,再放入新数。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int>q; // 双端队列
vector<int>res;
for(int i=0 ;i<nums.size();i++){ // 遍历nums
while(!q.empty() and nums[i] > q.back()) q.pop_back();
q.push_back(nums[i]);
if(i >= k and q.front() == nums[i-k]) q.pop_front(); //如果窗口前端的数是最大值,就可以弹出队首的数,窗口里的次大值变成最大值
if(i + 1 >= k) res.push_back(q.front()); // //每次把窗口里的最大值放入res中
}
return res;
}
};
933. 最近的请求次数
写一个 RecentCounter
类来计算特定时间范围内最近的请求。
请你实现 RecentCounter
类:
RecentCounter()
初始化计数器,请求数为 0 。int ping(int t)
在时间t
添加一个新请求,其中t
表示以毫秒为单位的某个时间,并返回过去3000
毫秒内发生的所有请求数(包括新请求)。确切地说,返回在[t-3000, t]
内发生的请求数。
保证 每次对 ping
的调用都使用比之前更大的 t
值。
示例 1:
输入: ["RecentCounter", "ping", "ping", "ping", "ping"] [[], [1], [100], [3001], [3002]] 输出: [null, 1, 2, 3, 3] 解释: RecentCounter recentCounter = new RecentCounter(); recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1 recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2 recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3 recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3
提示:
1 <= t <= 109
- 保证每次对
ping
调用所使用的t
值都 严格递增 - 至多调用
ping
方法104
次
解题思路:
1.题意:返回 [t-300,t ]内 请求的次数
2.可以使用队列存取请求,每次删除3000秒前的请求,然后最后输出队列长度即可。
3.注意:程序开始时会先初始化计数器。
class RecentCounter {
public:
queue<int>q;
RecentCounter() {
}
int ping(int t) {
q.push(t); // 第一个为NULL
while(q.front() < t - 3000) q.pop();
return q.size();
}
};
/**
* Your RecentCounter object will be instantiated and called as such:
* RecentCounter* obj = new RecentCounter();
* int param_1 = obj->ping(t);
*/
622. 设计循环队列
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k)
: 构造器,设置队列长度为 k 。Front
: 从队首获取元素。如果队列为空,返回 -1 。Rear
: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真。deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty()
: 检查循环队列是否为空。isFull()
: 检查循环队列是否已满。
示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3 circularQueue.enQueue(1); // 返回 true circularQueue.enQueue(2); // 返回 true circularQueue.enQueue(3); // 返回 true circularQueue.enQueue(4); // 返回 false,队列已满 circularQueue.Rear(); // 返回 3 circularQueue.isFull(); // 返回 true circularQueue.deQueue(); // 返回 true circularQueue.enQueue(4); // 返回 true circularQueue.Rear(); // 返回 4
提示:
- 所有的值都在 0 至 1000 的范围内;
- 操作数将在 1 至 1000 的范围内;
- 请不要使用内置的队列库。
解题思路:
1.使用链表实现循环队列。设置一个头指针和尾指针,初始时都指向头节点,在用两个变量维护循环队列最大容量和当前容量
2.当元素插入队列时,先判断当前容量是否小于最大容量,实际插入时链表尾插新节点,尾指针后移一位
3.当元素弹出队列时,先判断当前容量是否大于0,实际弹出时头指针后移一位即可
其余功能通过对队列当前容量的简单判断即可实现
class MyCircularQueue {
int maxlen,len;
struct node{
node *next;
int val;
};
node *head,*tail;
public:
MyCircularQueue(int k) {
maxlen = k;
len = 0;
head = new node;
head -> next = nullptr;
tail = head;
}
bool enQueue(int value) {
if(len >= maxlen) return false;
tail -> next = new node;
tail = tail->next;
tail -> next = nullptr;
tail -> val = value;
++len;
return true;
}
bool deQueue() {
if(len ==0 ) return false;
node *pre = head;
head = head -> next;
delete pre;
--len;
return true;
}
int Front() {
if(len) return head -> next ->val;
else return -1;
}
int Rear() {
if(len) return tail -> val;
else return -1;
}
bool isEmpty() {
return len==0;
}
bool isFull() {
return len == maxlen;
}
};
641. 设计循环双端队列
设计实现双端队列。
实现 MyCircularDeque
类:
MyCircularDeque(int k)
:构造函数,双端队列最大为k
。boolean insertFront()
:将一个元素添加到双端队列头部。 如果操作成功返回true
,否则返回false
。boolean insertLast()
:将一个元素添加到双端队列尾部。如果操作成功返回true
,否则返回false
。boolean deleteFront()
:从双端队列头部删除一个元素。 如果操作成功返回true
,否则返回false
。boolean deleteLast()
:从双端队列尾部删除一个元素。如果操作成功返回true
,否则返回false
。int getFront()
):从双端队列头部获得一个元素。如果双端队列为空,返回-1
。int getRear()
:获得双端队列的最后一个元素。 如果双端队列为空,返回-1
。boolean isEmpty()
:若双端队列为空,则返回true
,否则返回false
。boolean isFull()
:若双端队列满了,则返回true
,否则返回false
。
示例 1:
输入 ["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"] [[3], [1], [2], [3], [4], [], [], [], [4], []] 输出 [null, true, true, true, false, 2, true, true, true, 4] 解释 MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 circularDeque.insertLast(1); // 返回 true circularDeque.insertLast(2); // 返回 true circularDeque.insertFront(3); // 返回 true circularDeque.insertFront(4); // 已经满了,返回 false circularDeque.getRear(); // 返回 2 circularDeque.isFull(); // 返回 true circularDeque.deleteLast(); // 返回 true circularDeque.insertFront(4); // 返回 true circularDeque.getFront(); // 返回 4
提示:
1 <= k <= 1000
0 <= value <= 1000
insertFront
,insertLast
,deleteFront
,deleteLast
,getFront
,getRear
,isEmpty
,isFull
调用次数不大于2000
次
解题思路:
1.使用两个栈,栈1用来充当队列头,栈2用来充当队列尾。
2.在取元素时,如果该栈为空,但是另外的栈可能不为空,所以需要将另外一个栈中的数据拷贝过来; (getback()函数跟 getfront()函数)
3.在删除元素时,如果该栈为空,但是另外的栈可能不为空,所以需要从另外一个栈中进行删除;
class MyCircularDeque {
public:
int len = 0, maxlen = 0;
stack<int>front; // 存头
stack<int>back; // 存尾
MyCircularDeque(int k) {
maxlen = k;
}
bool insertFront(int value) {
if(len >= maxlen) return false;
front.push(value); ++len;
return true;
}
bool insertLast(int value) {
if(len >= maxlen) return false;
back.push(value); ++len;
return true;
}
bool deleteFront() {
if(len == 0) return false;
if(front.empty()) getback();
front.pop();
--len;
return true;
}
bool deleteLast() {
if(len == 0) return false;
if(back.empty()) getfront();
back.pop();
--len;
return true;
}
int getFront() {
if(isEmpty()) return -1;
if(front.empty()) getback();
return front.top();
}
int getRear() {
if(isEmpty()) return -1;
if(back.empty()) getfront();
return back.top();
}
bool isEmpty() {
return len==0;
}
bool isFull() {
return len == maxlen;
}
void getback(){
while(!back.empty()){
front.push(back.top());
back.pop();
}
return ;
}
void getfront(){
while(!front.empty()){
back.push(front.top());
front.pop();
}
return ;
}
};
/**
* Your MyCircularDeque object will be instantiated and called as such:
* MyCircularDeque* obj = new MyCircularDeque(k);
* bool param_1 = obj->insertFront(value);
* bool param_2 = obj->insertLast(value);
* bool param_3 = obj->deleteFront();
* bool param_4 = obj->deleteLast();
* int param_5 = obj->getFront();
* int param_6 = obj->getRear();
* bool param_7 = obj->isEmpty();
* bool param_8 = obj->isFull();
*/
50. Pow(x, n)
实现 pow(x, n) ,即计算 x
的整数 n
次幂函数(即,xn
)。
示例 1:
输入:x = 2.00000, n = 10 输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3 输出:9.26100
示例 3:
输入:x = 2.00000, n = -2 输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
n
是一个整数- 要么
x
不为零,要么n > 0
。 -104 <= xn <= 104
解题思路:
求x的n次方,n的数据范围很大,所以要用快速幂,防止时间超限。
快速幂:的基本思想是将b表示为二进制数,然后从右向左扫描该二进制数,每次遇到一个1,就对结果进行乘法运算。当然,有时候还需要使用取模运算来保证结果不会超过给定的模数n。
原理:
以3 ^ 13 为例:
首先将 b 转换成二进制:
那么 a ^ b 可以转换为:
![]()
class Solution {
public:
double quickproduct(double a,long long k){
double res = 1;
while(k){
if(k & 1) res *= a;
k >>= 1;
a *= a;
}
return res;
}
double myPow(double x, long long n) {
if( n > 0) return quickproduct(x,n);
if( n < 0) return 1/quickproduct(x,-n);
return 1.0;
}
};
以3 ^ 13 为例:
n(二进制) | a | res |
---|---|---|
1101 | 3 ^ (2^0) | 1 * 3^1 |
110 | 3 ^ (2^1) | 1 * 3^1 |
11 | 3 ^ (2^2) | 1 * 3^1 * 3^4 |
1 | 3 ^ (2^3) | 1 * 3^1 * 3^4 * 3^8 |