2024.7.28 刷题总结

2024.7.28

**每日一题**

699.掉落的方块,这道题最优解应该是用线段树的方法来解决,这里只给出最暴力的枚举解法。遍历原数组,每次记录左右两个端点的值,并且记录当前的高度。根据重叠的情况分析,如果方块出现重叠,那么当前高度至少为它们的和,所以每次取最大值即可。

class Solution {
public:
    vector<int> fallingSquares(vector<vector<int>>& positions) {
        int n = positions.size();
        vector<int> heights(n);
        for (int i = 0; i < n; i++) {
            int left1 = positions[i][0], right1 = positions[i][0] + positions[i][1] - 1;
            heights[i] = positions[i][1];
            for (int j = 0; j < i; j++) {
                int left2 = positions[j][0], right2 = positions[j][0] + positions[j][1] - 1;
                if (right1 >= left2 && right2 >= left1) {
                    heights[i] = max(heights[i], heights[j] + positions[i][1]);
                }
            }
        }
        for (int i = 1; i < n; i++) {
            heights[i] = max(heights[i], heights[i - 1]);
        }
        return heights;
    }
};

102.二叉树的层序遍历,这道题用的是广度优先搜索算法,用一个二元组来表示状态,表示每个节点和它所在的层数。步骤如下,当前根节点入队,当队列不为空时,求当前队列的长度s,依次从队列中取s个元素进行拓展,然后进行下一次迭代。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ret;
        if(!root){
            return ret;
        }

        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int cnt = q.size();
            ret.push_back(vector<int> ());
            for(int i =1;i<=cnt;i++){
                auto node=q.front();
                q.pop();
                ret.back().push_back(node->val);
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
            }
        }
        return ret;

    }
};

560.和为k的子数组,这道题考察的是前缀和的知识,但是如果我们直接用枚举前缀和相减来求解,时间复杂度就会很高,所以我们考虑用哈希表来辅助求解。首先我们需要先预处理出前缀和数组,根据前缀和的性质,我们需要在原来的数组长度上加一,储存第一位为0,方便后续的计算。然后我们开一个哈希映射map,用来储存对应的值出现的次数。从零开始枚举遍历前缀和数组,对于每个元素我们都要判断哈希表中是否存在K减去当前元素的值,如果有,那么就加上对应的次数,如果没有,就不更新答案,无论是否出现,我们都需要在哈希表中令当前前缀和元素对应的次数加1。按顺序遍历数组即可完成本题。

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> s(n + 1);
        for (int i = 0; i < n; i++) {
            s[i + 1] = s[i] + nums[i];
        }

        int ans = 0;
        unordered_map<int, int> cnt;
        for (int sj : s) {
            // 注意不要直接 += cnt[sj-k],如果 sj-k 不存在,会插入 sj-k
            ans += cnt.contains(sj - k) ? cnt[sj - k] : 0;
            cnt[sj]++;
        }
        return ans;
    }
};

215.数组中的第k个最大元素,这道题考察的是数组排序,由快速排序改进算法,还有堆排序,这里使用的是堆排序思想。首先建立一个大根堆,做k-1次删除操作之后,堆顶元素就是要求的答案。首先定义一个转化为大根堆的函数,每次从最后一个非叶节点开始向上遍历,判断当前节点和左右节点的大小关系来建立大根堆,然后再更新当前索引,即递归的思想,每次以当前节点为根节点往下交换节点,maxHeapify函数的作用是将当前节点作为根节点实现大根堆,buildMaxHeap函数的作用是建立初始大根堆,从数组大小的一半作为索引开始往上建立。先建立初始大根堆,然后循环n-k+1次,每次先把堆顶和堆尾节点交换,然后数组大小减一,代表把堆尾元素删除,即原来的堆顶元素,然后继续建立新的大根堆,直到取出第k大的元素。

class Solution {
public:
    void maxHeapify(vector<int>& a,int i,int heapsize){
        int l = i*2+1,r = i*2+2,largest = i;
        if(l<heapsize && a[l]>a[largest]){
            largest = l;
        }
        if(r<heapsize&&a[r]>a[largest]){
            largest = r;
        }
        if(largest!=i){
            swap(a[i],a[largest]);
            maxHeapify(a,largest,heapsize);
        }
    }

    void buildMaxHeap(vector<int>& a,int heapsize){
        for(int i =heapsize/2;i>=0;i--){
            maxHeapify(a,i,heapsize);
        }
    }

    int findKthLargest(vector<int>& nums, int k) {
        int heapsize = nums.size();
        buildMaxHeap(nums,heapsize);
        for(int i =nums.size()-1;i>=nums.size()-k+1;i--){
            swap(nums[0],nums[i]);
            heapsize--;
            maxHeapify(nums,0,heapsize);
        }

        return nums[0];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值