Leetcode:239 933 622 641 50

 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
  • insertFrontinsertLastdeleteFrontdeleteLastgetFrontgetRearisEmptyisFull  调用次数不大于 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 为例:

  1. 首先将 b 转换成二进制:(13)_{10} = (1101)_{2} = 1*2^3+1*2^2+0*2^1+1*2^0 = 2^3+2^2+2^0

  2. 那么 a ^ b 可以转换为:3^{13} = 3^{2^3}*3^{2^2}*3^{2^0}  

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(二进制)ares
11013 ^ (2^0)1 * 3^1
1103 ^ (2^1)1 * 3^1
113 ^ (2^2)1 * 3^1 * 3^4
13 ^ (2^3)1 * 3^1 * 3^4 * 3^8
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值