代码训练营Day.13 |

239. 滑动窗口最大值

1. LeetCode链接

239. 滑动窗口最大值 - 力扣(LeetCode)

2. 题目描述

代码训练营Day.13 |_第1张图片

3. 想法

耗时解法:

        首先讲耗时的解法。

        可以容易联想到用队列去代表这个滑动窗口,链表也行,但是队列更方便一点。

        如何去找队列中的最大值呢?

        每次都去遍历一次队列,找最大值,当然是最直接最暴力的解法。那这样,时间复杂度就是O(n * k)。在自定义队列中维护一个优先级链表,很耗时。

       先贴一个错误解法,死活不懂。

// 错误解法 第42用例,k = 50000, 输出应该全9999.但是错了,中间有几个不是9999
class MaxQue {
public:
    struct ListNode {
        int val;
        ListNode* next;
        ListNode(int x) : val(x), next(NULL) {}
    };
    queue q;
    ListNode* _dummyHead;
    // int _size;
    MaxQue(){
        _dummyHead = new ListNode(0);
        // _size = 0;
    }
    void paixu(int front, int back) {

    }
    int getMax() {
        // if (_dummyHead->next != NULL) return _dummyHead->next->val;
        return _dummyHead->next->val;
    }
    void push(int x) {
        q.push(x);

    }
    int front() {
        return q.front();
    }
    int pop() {
        int i = q.front();
        q.pop();
        return i;
    }
    int back() {
        return q.back();
    }
    void no_k_listSort(int num) {
        q.push(num);
        ListNode* cur = new ListNode(num);
        if (_dummyHead->next == NULL || _dummyHead->next->val < num) {
            // cur->next = NULL;
            _dummyHead->next = cur;
            return;
        }
        ListNode* pre = _dummyHead->next;
        while (pre != NULL) {
            if (pre->val >= num && (pre->next == NULL || pre->next->val <= num)) {
                // cur->next = pre->next;
                pre->next = cur;
                break;
            }
            pre = pre->next;
        }
    }
    void k_listSort(int first, int last) {
        // ListNode* cur = _dummyHead;
        
        // while (cur != NULL && cur->next != NULL) {
        //     if (cur->next->val == first) {
        //         ListNode* d = cur->next;
        //         cur->next = d->next;
        //         delete d;
        //     }
        // }
        
        // ListNode* d;
        if (_dummyHead->next != NULL && _dummyHead->next->val == first) {
            ListNode* cur = _dummyHead->next;;
            // cur = _dummyHead->next;
            _dummyHead->next = cur->next;
            delete cur;
        }
        
        q.pop();
        no_k_listSort(last);
    }

};

class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        MaxQue* q = new MaxQue();
        vector result;
        for (int i = 0; i < k; i++) {
            q->no_k_listSort(nums[i]);
        }
        result.push_back(q->getMax());
        for (int i = k; i < nums.size(); i++) {
            q->k_listSort(q->front(), nums[i]);
            result.push_back(q->getMax());
        }
        return result;
    }
};


         再来探讨代码随想录中的解法,单调队列。

        自定义一个队列,在队列中仅维护潜在最大值。这话说的,啥叫潜在最大值。事实上,就是,每进来一个新的元素,都把他前面比他小的“拉”出去,(需要用到可以从队尾pop的队列)。

        时间复杂度的解释,虽然每个元素会有pop_back操作和push_back操作,但是,在pop_back前,还有比较操作呀?

        但是,细想,比较操作好像,并比不了几次。小于了,就pop了;大于等于就不管了,又压入一个,直到又成为最后一个;

但是不可能又元素一直成为最后一个,如果他老是最后一个,那其他人就不会是最后一个了。所以,还是n的线性关系。

class MaxQue {
public:
    deque que;
    void pop(int val) {
        if (!que.empty() && que.front() == val) que.pop_front();
    }

    void push(int val) {
        while (!que.empty() && que.back() < val) {
            que.pop_back();
        }
        que.push_back(val);
    }
    int front() {
        return que.front();
    }
};

class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        MaxQue q;
        vector result;
        for (int i = 0; i < k; i++) q.push(nums[i]);
        result.push_back(q.front());
        for (int i = k; i < nums.size(); i++){
            q.pop(nums[i - k]);
            q.push(nums[i]);
            result.push_back(q.front());
        }
        return result;
    }
};

 347. 前k个高频元素

1. LeetCode链接

347. 前 K 个高频元素 - 力扣(LeetCode)

2. 题目描述

代码训练营Day.13 |_第2张图片

3. 想法

方法一:vector——sort

        利用哈希表,记录元素的频率,然后再把map腾到数组中。在数组中进行排序。

其中用到sort函数,需要自定义一个排序函数。注意,sort在类成员函数中,定义的排序函数也在类成员中,注意static。

class Solution {
public:
    static bool cmp (const pair& a, const pair& b) {
        return a.second > b.second;
    }
    vector topKFrequent(vector& nums, int k) {
        unordered_map map;
        for (int i = 0; i < nums.size(); i++) {
            auto f = map.find(nums[i]);
            if (f != map.end()) f->second++;
            else map.insert(pair(nums[i], 1));
        }
        vector> vec;
        for (auto x : map) {
            vec.push_back(x);
        }
        sort(vec.begin(), vec.end(), cmp);
        vector result;
        for (int i = 0; i < k; i++) {
            result.push_back(vec[i].first);
        }
        return result;
    }
};

 方法二:优先级队列(小顶堆)

        vector之后再排序,主要是需要维护整个的排序。而优先级队列(小顶堆),可以通过只维护k个元素的堆来实现该题。涉及到堆的删除和增加。不过,利用现成的就行。

        注意:priority_queue需要设计一个排序函数。

class Solution {
public:
    class mycomparison {
    public:
        bool operator()(const pair& lhs, const pair& rhs) {
            return lhs.second > rhs.second;
        }
    };
    vector topKFrequent(vector& nums, int k) {
        unordered_map map;

        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }

        priority_queue, vector>, mycomparison> pri_que;

        for (auto it = map.begin(); it != map.end(); it++) {
            pri_que.push(*it);
            if (pri_que.size() > k) {
                pri_que.pop();
            }
        }
        vector result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

你可能感兴趣的:(算法)