LeetCode Hot100 回顾(二)

news2024/11/17 1:33:43

子串

560.和为K的子数组

使用前缀和预处理一下题目给的数组, 然后用二重循环遍历一遍就可以了。

239.滑动窗口最大值

看题面比较容易想到的是用优先级队列来解决, 但是STL中的priority_queue不支持随机删除, 如果要用优先级队列来解决这道题的话比较复杂。这道题的一种正确解法是用单调队列来处理, 单调队列专门用来处理类似滑动窗口的区间最值问题。

接下来来看针对这道题, 单调队列是如何处理元素的入队和出队呢?

  • 入队: 从队列的后方入队, 弹出所有比当前元素(即待入队元素)小的元素, 因为这些元素都比当前元素小, 而且入队时间更早, 如果队列中有当前元素, 那么这些较小的元素永远不可能成为答案
  • 出队: 从队列的前方出队, 先弹出所有已经在区间外的元素, 然后得到的队头即是当前窗口的最大值
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        deque<int> que;  // 出队从前面, 入队从后面
        for (int i = 0; i < k; ++i) {
            while(!que.empty() && nums[i] > nums[que.back()]) que.pop_back();
            que.push_back(i);
        }
        res.push_back(nums[que.front()]);
        for (int i = k; i < nums.size(); ++i) {  // 枚举区间右端点
            while(!que.empty() && nums[i] > nums[que.back()]) que.pop_back();
            que.push_back(i);
            while(que.front() <= i-k) {
                que.pop_front();
            }
            res.push_back(nums[que.front()]);
        }
        return res;
    }
};

这类区间最值问题还可以使用ST表或线段树来解决, 不过针对滑动窗口的区间最值问题, 还是单调队列更简便一些。

普通数组

53.最大子数组和

从前往后遍历, 用一个变量来记录和, 如果这个变量记录到的和小于0, 就将它重置为0; 因为它不会给答案带来正面的收益, 算上它之后数组的和只会更小。注意要处理全是负数的数组的情况, 此时答案就为数组中最大的负数。

56. 合并区间

刚开始打算使用使用一个大小为1e4的数组来标记区间, 但是发现这种方法不能处理[1, 4], [5, 7]的例子, 这个例子实际没有产生重叠, 但依旧会在数组中产生一个连续的不为0的区间。正确处理方式是对所有区间按照左端点进行排序, 然后就可以方便的进行合并操作了。

189.轮转数组

使用区间拷贝的库函数, 几行就搞定了。空间复杂度为O(1)的方法可以通过旋转数组来实现。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k %= nums.size();
        vector<int> tmp(nums.rbegin(), nums.rbegin()+k);
        copy(nums.begin(), nums.end()-k, nums.begin()+k);
        copy(tmp.rbegin(), tmp.rend(), nums.begin());
    }
};

238.除自身以外数组的乘积

预处理前缀乘积和后缀乘积即可, 其中一个预处理数组可以使用一个变量来简化, 另一个预处理数组可以使用返回结果数组来代替。

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        vector<int> res(nums.size());
        res[0] = 1;
        for (int i = 0; i < nums.size()-1; ++i) {
            res[i+1] = res[i] * nums[i];
        }
        int t = 1;
        for (int i = nums.size()-1; i >= 0; --i) {
            res[i] *= t;
            t *= nums[i];
        }
        return res;
    }
};

矩阵

73.矩阵置零

直接说进阶方法,用第1行和第1列来记录第i行/第j列是否需要置零,第1行和第1列是否需要置0可以使用两个标志变量来记录。

54.螺旋矩阵

我采用了一种类似分治的想法,通过一个循环来不断输出数组,在循环的过程中,每输出一整行,剩下需要输出的矩阵的高就减1;同样每输出一整列,剩下需要输出的矩阵的宽就减1,直到剩余矩阵的宽或高变为0时,输出就结束了。通过一个变量来标记当前输出的方向。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        int height = matrix.size();
        int width = matrix[0].size();
        pair<int, int> pos(0, 0);
        /**
         *  移动方向
         * 1 --- 横向增大
         * 2 --- 纵向增大
         *
         * -1 --- 横向减小
         * -2 --- 纵向减小
         */
        int dir = 1;
        while(height && width) {
            if (dir == 1) {
                for (int i = 0; i < width; ++i) {
                    res.push_back(matrix[pos.first][pos.second+i]);
                }
                --height;
                pos.second += width-1;
                pos.first += 1;
                dir = 2;
            } else if (dir == 2) {
                for (int i = 0; i < height; ++i) {
                    res.push_back(matrix[pos.first+i][pos.second]);
                }
                --width;
                pos.first += height-1;
                pos.second -= 1;
                dir = -1;
            } else if (dir == -1) {
                for (int i = 0; i < width; ++i) {
                    res.push_back(matrix[pos.first][pos.second-i]);
                }
                --height;
                pos.second -= width-1;
                pos.first -= 1;
                dir = -2;
            } else if (dir == -2) {
                for (int i = 0; i < height; ++i) {
                    res.push_back(matrix[pos.first-i][pos.second]);
                }
                --width;
                pos.first -= height-1;
                pos.second += 1;
                dir = 1;
            }
        }
        return res;
    }
};

48.旋转图像

矩阵旋转90度,只需要沿对角线翻转矩阵,然后把矩阵逐行逆序即可。

240.搜索二维矩阵

遍历所有列, 二分查找。看了三叶的评论, 发现这个矩阵可以抽象成根节点在矩阵右上角的二叉搜索树, 太妙了。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {  // 抽象成二叉搜索树
        pair<int, int> pos{0, matrix[0].size()-1};
        while(true) {
            if (target > matrix[pos.first][pos.second]) {  // 往右子树查找
                if (pos.first == matrix.size()) return false;
                ++pos.first;
            } else if (target < matrix[pos.first][pos.second]) {
                if (pos.second == 0) return false;
                --pos.second;
            } else {
                return true;
            }
        }
        return false;
    }
};

链表

160.相交链表

可以知道, 如果两个链表相交, 那么从链表的末尾到相交节点的距离一定是相等的, 我们在遍历两个链表的过程中, 可以先将指针移动到距离链表结尾距离相等的位置, 然后同时移动两个指针, 移动过程中查看两个指针是否指向了同一个节点。

206. 翻转链表

头插法即可。这里学习一下如何使用递归来完成翻转, 这里的递归和以前用到的递归形式不太一样, 不太好理解

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode* p = head;
        ListNode* newHead = reverseList(head->next);  // (1)假设head后的所有节点都完成了翻转
        head->next->next = head;  // (2)翻转后head的下一个节点变成了head前面紧邻的节点
        head->next = nullptr;  // (3)head->next置空
        return newHead;  // 返回翻转后的新头节点
    }
};

我们现在取一个中间状态来讲解一下,假设现在递归调用到了处理节点2的情况,执行完(1)后链表的情况是这样的

执行完(2)之后链表情况是这样的

执行完(3)之后是这样的

234.回文链表

判断回文串的方式就是找到中间节点, 使用两个指针分别向两边移动, 依次比较即可, 难点主要在链表不能简单的找到它的前驱节点, 我们可以利用递归函数的性质来比较

class Solution {
private:
    ListNode* p;
    int pos;
public:
    bool isPalindrome(ListNode* head) {
        ListNode* slow = head, *fast = head;
        pos = 0;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            ++pos;
        }
        if (fast) p = slow->next;
        else p = slow;
        return cmp(head, 0);
    }
    bool cmp(ListNode* head, int cnt) {
        if (cnt < pos) {
            if (cmp(head->next, cnt+1)) {
                if (head->val == p->val) {
                    p = p->next;
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1423572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT + opengl 环境搭建(glfw, glad),创建一个简单窗口

一.下载glfw&#xff0c;glad并编译 1.glfw个人理解就是对底层opengl的一些基本接口的封装&#xff0c;提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入。glfw的下载地址&#xff1a;Download | GLFW&#xff0c;下载完成后…

SpringBoot 结合 liteflow 规则引擎使用

1、前言 在日常的开发过程中&#xff0c;经常会遇到一些串行或者并行的业务流程问题&#xff0c;而业务之间不必存在相关性。 在这样的场景下&#xff0c;使用策略和模板模式的结合可以很好的解决这个问题&#xff0c;但是使用编码的方式会使得文件太多,在业务的部分环节可以…

15EG使用vivado2023.1建立hello world工程

1:打开软件建立工程 2:使用vivado创建设计模块并生成bit文件 3:导出硬件平台&#xff0c;使用vitis建立工程 4:使用vitis创建应用程序项目 5:硬件设置与调试 1:打开软件建立工程 打开VIVADO2023.1 创建一个新的工程 输入项目名称和地址&#xff0c;下面那个选项为是否…

Web开发7:Git版本控制

在开发中&#xff0c;版本控制是一个不可或缺的工具。它能够帮助开发者跟踪和管理代码的变化&#xff0c;协同工作&#xff0c;并且有效地处理代码的冲突。其中&#xff0c;Git是最流行和广泛使用的版本控制系统之一。在本篇文章中&#xff0c;我们将深入探讨Git版本控制的基础…

2024年,AI 掀起数据与分析市场的新风暴

2024 年伊始&#xff0c;Kyligence 联合创始人兼 CEO 韩卿在其公司内部的飞书订阅号发表了多篇 Rethink Data & Analytics 的内部信&#xff0c;分享了对数据与分析行业的一些战略思考&#xff0c;尤其是 AI 带来的各种变化和革命&#xff0c;是如何深刻地影响这个行业乃至…

基于SSM的高校班级同学录网站设计与实现(有报告)。Javaee项目,ssm项目。

演示视频&#xff1a; 基于SSM的高校班级同学录网站设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm项目。 项目介绍&#xff1a; Javaee项目&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

leetcode 28.找出字符串中第一个匹配项的下标(python版)

需求 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。 如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入&#xff1a;haystack…

网工内推 | 网络安全工程师专场,大平台,六险一金

01 汽车之家 招聘岗位&#xff1a;高级网络安全工程师 职责描述&#xff1a; 1、负责公司网站、系统与产品的漏洞扫描、渗透测试与安全评估工作&#xff1b; 2、负责公司安全系统与安全设备的运维&#xff0c;负责公司网络安全监控管理&#xff1b; 3、负责公司安全事件的应急…

FileZilla 的安装与使用

目录 一. FileZilla 是什么二. FileZilla 的安装1. 下载 FileZilla2. 安装 三. FileZilla 的使用 一. FileZilla 是什么 FileZilla 是一个免费的开源 FTP&#xff08;文件传输协议&#xff09;客户端软件&#xff0c;用于在计算机之间传输文件。它提供了一个直观的用户界面&am…

sql注入,布尔盲注和时间盲注,无回显

布尔盲注 通过order by分组可以看到&#xff0c;如果正确会i显示you are in&#xff0c;错误则无任何提示&#xff0c;由此可以判断出&#xff0c;目前只显示对错&#xff0c;此外前端不会显示任何数据 也就是说&#xff0c;目前结果只有两种&#xff0c;在这种只有两种变量的…

Unity 自动轮播、滑动轮播

如图所示&#xff0c;可设置轮播间隔&#xff0c;可左右滑动进行轮播 1.在UGUI创建个Image&#xff0c;添加自动水平组件 2.添加并配置脚本 3.代码如下&#xff0c;都有注释 using UnityEngine; using UnityEngine.UI;public class IndicatorManager : MonoBehaviour {public …

鸿蒙不再兼容安卓,那么鸿蒙开发者是否会大增?

华为的纯血版鸿蒙已出现。紧接着各大厂商都纷纷加入原生应用开发当中&#xff0c;其中包括支付宝、京东、美团等一线大厂&#xff0c;200 多应用厂商正在加速开发鸿蒙原生应用。鸿蒙生态设备数量仅历时 5 个月即从 7 亿增长至 8 亿。 而鸿蒙的开发不止应用层&#xff0c;它是以…

6.3 内存池模式

Bruce Powel Douglass大师介绍-CSDN博客https://blog.csdn.net/ChatCoding/article/details/134665868嵌入式软件开发从小工到专家-CSDN博客https://blog.csdn.net/ChatCoding/article/details/135297955C嵌入式编程设计模式源码-CSDN博客https://blog.csdn.net/ChatCoding/art…

根文件系统之initramfs

问题抛出&#xff1a; 1.系统启动时文件系统功能的实现 1.bootloader支持 1.uboot启动 ——典型的arm设备的选择。 情景1&#xff1a;使用initrd或initramfs&#xff0c;内核和根文件系统作为不同镜像时&#xff0c;uboot负责提供启动参数&#xff1b;加载根文件系统到内存…

C++ 设计模式之解释器模式

【声明】本题目来源于卡码网&#xff08;卡码网KamaCoder&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 --什么是解释器模式&#xff08;第22种设计模式&#xff09; 解释器模式&#xff08;Interpreter…

【INTEL(ALTERA)】带有浮点单元 (FPU) Nios® V/g 处理器在 英特尔® Cyclone10 GX 设备中执行不正确的浮点运算

说明 由于 英特尔 Quartus Prime Pro Edition 软件版本 23.3 存在一个问题&#xff0c;当使用 Nios V/g 处理器并在 英特尔 Cyclone 10 GX 设备中启用 FPU 时&#xff0c;浮点运算无法按预期进行。 Nios V/g 处理器 – 启用浮点单元 解决方法 请勿在 英特尔 CycloneNios 10 G…

张维迎《博弈与社会》笔记(2)导论:个体理性与社会最优:协调与合作问题

有节选&#xff0c;相当于按照自己的方式将内容组织了下吧&#xff1f; 协调与合作问题 什么是一个社会面临的基本问题&#xff1f; 这似乎是一个我们每一个人都可以触摸得到但又难以说清的问题&#xff0c;因为在不同的语境下&#xff0c;“社会”一词的内涵有所差异。但其基…

火山引擎ByteHouse:分析型数据库如何设计并发控制?

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 分析型数据库设计并发控制的主要原因是为了确保数据的完整性和一致性&#xff0c;同时提高数据库的吞吐量和响应速度。并发控制可以防止多个事务同时对同一数据进行…

ICMPv6报文解析及NAT处理

ICMPv6报文概述 参考RFC4443和RFC2460 ICMPv6报文是IPv6在internal control management protocol&#xff08;ICMP&#xff09;的基础之上做了一些改动&#xff0c;得到了ICMPv6协议&#xff0c;IPv6的next_header为58。 Message general format 每条ICMPv6消息之前都有一个…

从零开始的OpenGL光栅化渲染器构建6-PBR光照模型

前言 PBR&#xff0c;或者基于物理的渲染(Physically Based Rendering)&#xff0c;它指的是一些在不同程度上都基于与现实世界的物理原理更相符的基本理论所构成的渲染技术的集合。正因为基于物理的渲染目的便是为了使用一种更符合物理学规律的方式来模拟光线&#xff0c;因此…