Leetcode 刷题总结

最近正在刷题,时间久了一些想法可能就忘记了,特此写此片论文,记录一下一些题目的解体思路,供以后参看。

239. 滑动窗口最大值

题目:

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。

思路:

题意非常明确查找窗口内的最大值,数据范围大概1e5左右,通常双重循环即可解决,但是数据范围过大,会导致超时。因此采用一个算法时间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))是目前的最优解。
我们在这里采用有限队列解决这个问题,时间复杂度符合要求。优先队列中存储两种数据,一种数据为当前数值的大小,另一种为位置信息,每次取出优先队列中的最大值,若最大值不再窗口之内,则继续取,直到符合要求位置,则该值为当前窗口的最大值。

代码:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int ans = 0;
        vector<int>res;
        priority_queue<pair<int, int>>que;//数值信息,和位置信息
        for(int i = 0; i < k; i++)que.emplace(nums[i], i);
        res.push_back(que.top().first);
        for(int i = k; i < nums.size(); i++){
            que.emplace(nums[i], i);
            while(!que.empty() && que.top().second <= i-k)que.pop();//剔除不符合要求的数据
            res.push_back(que.top().first);
        }
        return res;
    }
};

41. 缺失的第一个正数

题目:

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

思路:

时间复杂度 O ( n ) O(n) O(n)的时间内可以轻松解决,通常采用数组或者hash(c++中词用stl中的map或者unordered_map)进行标记。但是虽然时间复杂度满足条件,但是空间复杂度同样的也是 O ( n ) O(n) O(n)的,如果在不采用过多的额外的空间进行标记内,一个常规的用法,就是采用原始数组进行标记,通过正负号进行标记这些数据。
但是在处理的过程中需要注意一下几点:

  1. 数据中已经存在的负数和0怎么处理:将其标记为一个不再取值范围之内数据
    2)如果数据已经被标记为负数之后,如连续出现1 1,再次标记之后将相互抵消,因此需要判断这个位置为负数之后,再进行标记。
    3)坐标位置由于从0开始的,则我们需要将这些数据进行往前挪一下位置。
class Solution {
public:
    const int mxn = 1e6;
    int firstMissingPositive(vector<int>& nums) {
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] <= 0 || nums[i] > nums.size())nums[i] = mxn;
        }// 处理0和负数
        for(int i = 0; i < nums.size(); i++){
            if(abs(nums[i]) == mxn)continue;//0和负数进行判断
            else{
                if(nums[abs(nums[i])-1] < 0)continue;//当前位置已经被标记,则无需重新标记
                else nums[abs(nums[i])-1] *= -1;// 尚未标记,则继续
            }

        }
        int ans = nums.size()+1;
        for(int i = 0; i < nums.size(); i++){// 查找相为正数的位置,则是我们需要的数据
            if(nums[i] > 0){
                ans = i+1;
                break;
            }
        }
        return ans;
    }
};

295. 数据流的中位数

题目:

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 arr = [2,3,4] 的中位数是 3 。
例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。
实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。
  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

思路:

常规的方式是排序的方式求中位数,但是每次重新进行排序,时间复杂度为 O ( n 2 ) O(n^2) O(n2), 因此我们只需要维护中间的两个中间值,我们采用两个堆,大顶堆,小顶堆。新增加的数据放入大顶堆,当两边维度不一致时,将大顶堆的最大值放入小顶堆。维持小顶堆中的数据始终大于大顶堆。

代码:

class MedianFinder {
public:
    priority_queue<int>large_heap;
    priority_queue<int,vector<int>,greater<int> > small_heap;
    MedianFinder() {

    }
    
    void addNum(int num) {
        if(large_heap.empty()){large_heap.push(num); return;}
        
        if(large_heap.size() == small_heap.size()){
            large_heap.push(num);
            int temp = large_heap.top();
            large_heap.pop();
            small_heap.push(temp);
            temp = small_heap.top();
            small_heap.pop();
            large_heap.push(temp);
            return;
        }

        if(large_heap.size() > small_heap.size()){
            large_heap.push(num);
            int temp = large_heap.top();
            large_heap.pop();
            small_heap.push(temp);
            return;
        }
    }
    
    double findMedian() {
        if(large_heap.size() == small_heap.size()){
            cout<<large_heap.size()<<" "<<small_heap.size()<<endl;
            return (large_heap.top() + small_heap.top())/2.0;

        }
        else return large_heap.top();
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

23. 矩阵中的路径

题目:

请设计一个函数,用来判断在一个矩阵中是否存在一条路径包含的字符按访问顺序连在一起恰好为给定字符串。
路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。
在这里插入图片描述

思路:

思路源于blibli大雪菜(yxc), dfs爆搜, 去找符合条件的内容。

代码:

class Solution {
public:
    bool dfs(int x, int y, int u, string str,vector<vector<char>>& matrix){
        if(matrix[x][y] != str[u])return false;
        if (u == str.size()-1)return true;
        
        int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
        char t = matrix[x][y];
        matrix[x][y] = '*';
        for(int i = 0; i < 4; i++){
            int xx = x + dx[i], yy = y + dy[i];
            if(xx >= 0 && xx < matrix.size() && yy >= 0 && yy < matrix[0].size()){
                if(dfs(xx, yy, u+1, str, matrix))return true;
            }
            
        }
        matrix[x][y] = t;
        return false;
    }
    bool hasPath(vector<vector<char>>& matrix, string &str) {
        for(int i = 0; i < matrix.size(); i++){
            for(int j = 0; j < matrix[0].size(); j++){
                if(matrix[i][j] == str[0]){
                    if(dfs(i, j, 0, str, matrix))return true;
                }
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值