leetcode 热题 100(部分)C/C++

leetcode 热题 100

双指针

盛最多水的容器 【mid】【双指针】

在这里插入图片描述
思路:
好久没写代码sb了,加上之前写的双指针并不多,以及有点思维定势了。我对双指针比较刻板的印象一直是两层for循环i,j,初始时i,j都位于左界附近,但是对于第i次的内层循环,j只需要从第i-1次内层循环停下时的j开始循环,即内层的循环变量j一直在增加,而不会减少,故双指针复杂度O(n)
然鹅,本题利用双指针l,r,初始分别位于左界和右界,之后++l--r,这样子移动。
至于如何移动,写出容器容量公式便很容易想出V=(r - l - 1) * min(height[l], height[r])。为取得Vmax,考虑无论移动l or r,都会使得宽d = r - l - 1 变小,故考虑如何使得min(height[l], height[r])变大,容易发现应该移动height小的那一个。
AC代码

class Solution {
public:int maxArea(vector<int>& height) {int n = height.size();int l = 0, r = n - 1;int s = (r - l) * min(height[l], height[r]);int res = s;while(l < r){if(height[l] < height[r]) ++l;else --r;s = (r - l) * min(height[l], height[r]);res = max(res, s);}return res;}
};

三数之和 【mid】【双指针】

在这里插入图片描述
思路:
与上一题类似。
先排序,之后搜一遍。
对于nums[i],需要从右边找出两个数字使得和为-nums[i]
双指针l,r初始分别为左界和右界,据nums[l] + nums[r]-nums[i]的大小关系决定移动哪个指针即可。
另外对于去重,可直接通过set逃课。
AC代码

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {int n = nums.size();vector<vector<int>> res;set<vector<int>> st;sort(nums.begin(), nums.end());int a, sum, last = -5000000;int l, r;bool flag;for(int i = 0; i < n; ++i){if(nums[i] == last) continue;else{last = nums[i];l = i + 1; r = n - 1;a = -nums[i];while(l < r){sum = nums[l] + nums[r];if(sum > a) --r;else if(sum < a) ++l;else {vector<int> vt;vt.push_back(nums[i]);vt.push_back(nums[l]);vt.push_back(nums[r]);st.insert(vt);++l;}}}}for(auto x : st) res.push_back(x);return res;}
};

接雨水【hard】【双指针/单调栈】

在这里插入图片描述
思路:
【解1】:预处理(对应官方题解dp解法)
考虑每个洼地可容纳的雨水,取决于这个洼地左侧和右侧的最高的高地的较小值。对于每个洼地左侧和右侧的最高的高地,预处理即可。
【解2】:双指针
思路同解1,只不过不做预处理,而是用双指针l,r初始分别为左界右界,移动过程中,分别维护扫过区域的最大值,每次移动最大值较小的那一侧,然后判断移动之后是洼地还是高地,洼地则计算接的雨水,高地则更新单侧最大值。
关于为什么移动最大值较小的那一侧,假设较高的一侧是r
移动r侧,由于移动之后可能是高地or洼地,对于高地,不计算贡献,其实无所谓,但是对于洼地,需要计算贡献,此时贡献取决于洼地两侧最高的高地的较小值,然而左侧最高的高地其实是不确定的,故无法计算。倘若移动是l的一侧,虽然右侧最高的高地也是不确定的,但至少可以确定的是右侧的高地一定比左侧的高,故可以计算正确的贡献。
【解3】:单调栈
构造一个单减栈(栈底>栈顶)。对于单调栈,其实每个元素都会进栈一次。
对于遍历到的当前元素,若<栈顶元素,入栈
否则,说明存在可以积水的洼地,此时需要弹出栈顶元素,可积的雨水取决于洼地的宽度(据两侧高地的距离)及可积雨水的高地,循环处理,直至当前元素可以入栈。(此过程官方视频题解动画容易理解)。
AC代码:
预处理:

class Solution {
public:int trap(vector<int>& height) {int n = height.size();int res = 0;int lmx[n + 5], rmx[n + 5];lmx[0] = height[0], rmx[n - 1] = height[n - 1];for(int i = 1; i < n; ++i) lmx[i] = max(lmx[i - 1], height[i]);for(int i = n - 2; i >= 0; --i) rmx[i] = max(rmx[i + 1], height[i]); int mx1, mx2, h;for(int i = 0; i < n; ++i){mx1 = lmx[i], mx2 = rmx[i];h = min(mx1, mx2);res += (h - height[i]);}return res;}
};

双指针:

class Solution {
public:int trap(vector<int>& height) {int n = height.size();int res = 0;int l = 0, r = n - 1;int lmx = height[0], rmx = height[n - 1];while(l < r){if(lmx < rmx){++l;if(lmx > height[l]) res += lmx - height[l];else lmx = height[l];}else{--r;if(rmx > height[r]) res += rmx - height[r];else rmx = height[r];}}return res;}
};

单调栈:

class Solution {
public:int trap(vector<int>& height) {stack<int> st;int n = height.size();int res = 0;for(int i = 0; i < n; ++i){while(!st.empty() && height[i] > height[st.top()]){int tp = st.top();st.pop();if(st.empty()) break;int l = st.top();int d = i - l - 1;int h = min(height[l], height[i]) - height[tp];res += d * h;}st.push(i);}return res;}
};

子串

最小覆盖字串【hard】【双指针/滑动窗口】

在这里插入图片描述
思路:
先找出左边界为字符串s的左边界且能覆盖t的最小子串。
之后,利用双指针/滑动窗口的思想,交替移动左右指针l,r
具体规则如下:
若当前子串能够覆盖,则++l,否则++r,每次移动后判断新的子串是否能够覆盖并且是否变小,保存最小能覆盖的子串长度以及其左右边界l,r
关于如何判断,只需在移动的过程中维护好如下容器or变量便显而易见。

map<char, int> mp; 			  //hash,'a'~'z'对应1~26,'A'~'Z'对应27~52
int cnt_s[64]				  //cnt_s[i]表示当前子串s[l~r]中i对应的字母个数,cnt_t[i]表示
int cnt_t[64];				  //cnt_t[i]表示t串中i对应的字母一共有几个
int num = 0, cnt = 0;		  //num表示t串一共有多少个不同的字母,cnt表示当前子串s[l~r]已经覆盖了t中的字母个数
int l, r;					  //当前正在处理的子串s[l~r]
int min_l, min_r, mi = inf;   //目前所有处理的子串中能覆盖的最小子串的左右边界及长度

AC代码:

class Solution {
public:string minWindow(string s, string t) {const int inf = 0x3f3f3f3f;int len1 = s.size(), len2 = t.size();map<char, int> mp;int cnt_s[64], cnt_t[64];int num = 0, cnt = 0;int l, r, min_l = 0, min_r = 0, mi = inf; string str;for(char ch = 'a'; ch <= 'z'; ++ch) mp[ch] = ch - 'a' + 1;for(char ch = 'A'; ch <= 'Z'; ++ch) mp[ch] = ch - 'A' + 1 + 26;for(int i = 0; i < len2; ++i) ++cnt_t[mp[t[i]]];for(int i = 1; i < 55; ++i) if(cnt_t[i]) ++num;l = 0, r = -1;while(r < len1){if(cnt == num){if(cnt_s[mp[s[l]]] == cnt_t[mp[s[l]]]) --cnt;--cnt_s[mp[s[l++]]];}else{++cnt_s[mp[s[++r]]];if(cnt_s[mp[s[r]]] == cnt_t[mp[s[r]]]) ++cnt;}if(cnt == num && r - l + 1 < mi){mi = r - l + 1;min_l = l, min_r = r;} }if(mi == inf) return "";else {str = s.substr(min_l, mi);return str;}}
};

普通数组

轮转数组【mid】【数论/gcd】

在这里插入图片描述
思路
给出空间O(1),且不用reverse的方法。(官方题解推导比较清楚)。
维护两个变量postmp,分别表示现在的位置和对应位置上的值,由此,更新只需pos = (pos + k) % n,swap(nums[pos], tmp),当pos回到最开始的位置时,我们称这是完成了一趟修改,此时应该停下,然鹅有的元素并没有遍历到。(只将下标为gcd(k,n)的元素遍历了,可证,另见类似题目,2015ICPC沈阳,跳青蛙🐸容斥),故需要将pos+1,再依次为开始,继续上述操作,直至回到开始位置并遍历全部位置。
接下来考虑需要几趟(根据上面结论,其实可知需要gcd(n,k)趟)。假设转了a圈,遍历了b个元素,则an=bk,故an一定是n,k的倍数,又因为我们在第一次回到起点时便结束了,故a应尽可能的小,由此an=lcm(n,k),故b=lcm(n,k)/k,即需要遍历的趟数cnt=n/b=gcd(n,k)
AC代码:

class Solution {
public:int gcd(int a, int b){return b == 0 ? a : gcd(b, a % b);}void rotate(vector<int>& nums, int k) {int n = nums.size();k %= n;int cnt = gcd(n, k);for(int i = 0; i < cnt; ++i){int pos = i;int tmp = nums[i];while(true){pos = (pos + k) % n;swap(nums[pos], tmp);if(pos == i) break;}}}
};

缺失的第一个正数 【Hard】【置换/原地哈希】

在这里插入图片描述
思路:
【方法1】:置换(类似于上一个题目)

  • nums[i]<=0||nums[i]>n的元素统一处理。(设置为较大值或数组中出现过的某个1~n的值)。
  • 对于x = nums[i],考虑swap(nums[i], nums[x-1]),即将nums[i]放到他应该在的位置上,如此循环下去,但是注意到当nums[i] == nums[x-1]时会进入死循环。
  • 所有1~n之间的数字都应当被放到对应的位置上,故最后遍历一遍数组,找到第一个不在对应位置之上的元素,便可知答案。
    【方法2】:改进开bool型数组,需要空间复杂度O(n),原始数组nums同时充当bool数组(原地哈希)
    首先,给出开bool数组的方法,开一个大小为n+5bool数组flag,flag[i]=true表示i出现,为此只需要找第一个flag[i]==falsei即可。
    改进方法如下:
  • 同方法1。
  • 通过第一步nums数组中应当只有正数。此时,对于一个1~n之间的数字x,我们就将nums[x - 1]中的元素修改为-nums[x - 1](主要不要多次修改,以防负负得正)。即nums数组中元素的正负代表上述bool型数组的truefalse,绝对值代表对应元素的值。
  • 与方法1类似。

AC代码:
【方法1】:置换

class Solution {
public:int firstMissingPositive(vector<int>& nums){int n = nums.size();for(int i = 0; i < n; ++i) while(nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) swap(nums[i], nums[nums[i] - 1]);for(int i = 0; i < n; ++i) if(nums[i] != i + 1) return i + 1;return n + 1;}
};

【方法2】:原地哈希

class Solution {
public:int firstMissingPositive(vector<int>& nums){int n = nums.size();int x;bool flag = false;for(auto x: nums) if(x == 1) flag = true;if(!flag) return 1;for(int i = 0; i < n; ++i) if(nums[i] <= 0 || nums[i] > n) nums[i] = 1;for(int i = 0; i < n; ++i){x = abs(nums[i]) - 1;nums[x] = -abs(nums[x]);}for(int i = 0; i < n; ++i) if(nums[i] > 0) return i + 1;return n + 1;}};

矩阵

矩阵置零【mid】【原地/随机】

在这里插入图片描述
思路:
【方法1】:原地
比较容易想到,开一个长度为n和长度为mbool型数组,分别表示第i行和第j列是否有0。这样空间复杂度O(n+m)。优化方法是用原数组的第一行和第一列充当这个bool数组。
用两个bool型变量colrow表示第1列,第1行是否有0,之后对于matrix[i][j]==0,将matrix[i][0]matrix[0][i]标记为0
【方法2】:随机
这个问题的关键是,只会把一开始就有的0所在的行和列全部置为0,后来的出现0不会操作。容易想到的一个思路就是先把有0的行和列中不是0的数字置为一个奇怪的数字(比如inf或是-inf),最后再把这些数改为0,但是发现取值为int的最小值到最大值,所以不行。但是n,m最大为200,随机生成的一个int在矩阵中出现的概率极低,故我们随机生成一个数字作为上述中的奇怪数字即可。(当然是需要判断的,如果运气不好,随机生成的数字正好出现了,就再随机生成一个)

AC代码:
【方法1】:原地

class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {int n = matrix.size();int m = matrix[0].size();bool col = false, row = false; //column = 列,row = 行for(int i = 0; i < n; ++i){if(!matrix[i][0]){col = true;break;}}for(int i = 0; i < m; ++i){if(!matrix[0][i]){row = true;break;}}for(int i = 1; i < n; ++i){for(int j = 1; j < m; ++j){if(!matrix[i][j]) matrix[i][0] = matrix[0][j] = 0;}}for(int i = 1; i < n; ++i){for(int j = 1; j < m; ++j){if(!matrix[i][0] || !matrix[0][j]) matrix[i][j] = 0; }}if(col) for(int i = 0; i < n; ++i) matrix[i][0] = 0;if(row) for(int i = 0; i < m; ++i) matrix[0][i] = 0;}
};

【方法2】:随机

class Solution {
public:int st_rand(vector<vector<int>>& matrix){int xx = matrix.size();int yy = matrix[0].size();srand(time(NULL));int st;bool flag;while(true){st = rand();flag = false;for(int i = 0; i < xx; ++i){for(int j = 0; j < yy; ++j){if(matrix[i][j] == st) {flag = true;break;}}if(flag) break;}return st;}}void work(vector<vector<int>>& matrix, int x, int y, int st){int xx = matrix.size();int yy = matrix[0].size();for(int i = 0; i < xx; ++i) if(matrix[i][y] != 0) matrix[i][y] = st;for(int i = 0; i < yy; ++i) if(matrix[x][i] != 0) matrix[x][i] = st;}void setZeroes(vector<vector<int>>& matrix) {int xx = matrix.size();int yy = matrix[0].size();int st = st_rand(matrix);for(int i = 0; i < xx; ++i){for(int j = 0; j < yy; ++j){if(matrix[i][j] == 0) work(matrix, i, j, st);}}for(int i = 0; i < xx; ++i){for(int j = 0; j < yy; ++j){if(matrix[i][j] == st) matrix[i][j] = 0;}}}
};

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

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

相关文章

Open CASCADE学习|刚体( TopoDS_Shape)按某种轨迹运动,停在指定位置上

今天实现如下功能&#xff1a;刚体做做螺旋运动&#xff0c;轨迹已知&#xff0c;求刚体在每个位置上的所占据的空间&#xff0c;就是把刚体从初始位置变换到该位置。 这里的刚体是一个砂轮截面&#xff0c;螺旋运动轨迹由B样条曲线拟合&#xff0c;通过Frenet标架确定运动轨迹…

iOS使用CoreML运用小型深度神经网络架构对图像进行解析

查找一个图片选择器 我用的是ImagePicker 项目有点老了&#xff0c;需要做一些改造&#xff0c;下面是新的仓库 platform :ios, 16.0use_frameworks!target learnings dosource https://github.com/CocoaPods/Specs.gitpod ImagePicker, :git > https://github.com/KevinS…

Python之Opencv进阶教程(1):图片模糊

1、Opencv提供了多种模糊图片的方法 加载原始未经模糊处理的图片 import cv2 as cvimg cv.imread(../Resources/Photos/girl.jpg) cv.imshow(girl, img)1.1 平均值 关键代码 # Averaging 平均值 average cv.blur(img, (3, 3)) cv.imshow(Average Blur, average)实现效果 1.2…

STM32F407 FSMC并口读取AD7606

先贴一下最终效果图.这个是AD7606并口读取数据一个周期后的数据结果. 原始波形用示波器看是很平滑的. AD7606不知为何就会出现干扰, 我猜测可能是数字信号干扰导致的. 因为干扰的波形很有规律. 这种现象基本上可以排除是程序问题. 应该是干扰或者数字信号干扰,或者是数字和模拟…

基于Spring Boot的餐厅点餐系统

基于Spring Boot的餐厅点餐系统 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.3.9 部分系统展示 管理员登录界面 用户注册登录界面 …

​如何使用ArcGIS Pro进行洪水淹没分析

洪水淹没分析是一种常见的水文地理信息系统应用&#xff0c;用于模拟和预测洪水事件中可能受到淹没影响的地区&#xff0c;这里为大家介绍一下ArcGIS Pro进行洪水淹没分析的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的DEM数据&…

Python学习笔记-Flask接收post请求数据并存储数据库

1.引包 from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy 2.配置连接,替换为自己的MySQL 数据库的实际用户名、密码和数据库名 app Flask(__name__) #创建应用实列 app.config[SQLALCHEMY_DATABASE_URI] mysqlpymysql://ro…

鸿蒙OS开发实例:【应用事件打点】

简介 传统的日志系统里汇聚了整个设备上所有程序运行的过程流水日志&#xff0c;难以识别其中的关键信息。因此&#xff0c;应用开发者需要一种数据打点机制&#xff0c;用来评估如访问数、日活、用户操作习惯以及影响用户使用的关键因素等关键信息。 HiAppEvent是在系统层面…

适用于 Linux 的 Windows 子系统安装初体验

1、简述 Windows Subsystem for Linux (WSL) 是 Windows 的一项功能&#xff0c;允许您在 Windows 计算机上运行 Linux 环境&#xff0c;而无需单独的虚拟机或双重启动。 WSL 旨在为想要同时使用 Windows 和 Linux 的开发人员提供无缝且高效的体验。 使用 WSL 安装和运行各种 L…

【javaScript】DOM编程入门

一、什么是DOM编程 概念&#xff1a;DOM(Document Object Model)编程就是使用document对象的API完成对网页HTML文档进行动态修改&#xff0c;以实现网页数据和样式动态变化的编程 为什么要由DOM编程来动态修改呢&#xff1f;我们就得先理解网页的运行原理&#xff1a; 如上图&a…

IO流:字节流、字符流、缓冲流、转换流、数据流、序列化流 --Java学习笔记

目录 IO流 IO流的分类 IO流的体系 字节流&#xff1a; 1、Filelnputstream(文件字节输入流) 2、FileOutputStream(文件字节输出流) 字节流非常适合做一切文件的复制操作 复制案例&#xff1a; try-catch-finally 和 try-with-resource 字符流 1、FileReader(文件字符…

ALPHA开发板上的PHY芯片驱动:LAN8720驱动

一. 简介 前面文章了解到&#xff0c;Linux内核是有提供 PHY通用驱动的。 本文来简单了解一下ALPHA开发板上的 PHY网络芯片LAN8720的驱动。是 LAN8720芯片的公司提供的 PHY驱动。 二. ALPHA开发板上的PHY芯片驱动&#xff1a;LAN8720驱动 我 们 来 看 一 下 LAN8720A 的 …

输入url到页面显示过程的优化

浏览器架构 线程&#xff1a;操作系统能够进行运算调度的最小单位。 进程&#xff1a;操作系统最核心的就是进程&#xff0c;他是操作系统进行资源分配和调度的基本单位。 一个进程就是一个程序的运行实例。启动一个程序的时候&#xff0c;操作系统会为该程序创建一块内存&a…

HDLbits 刷题 --Always nolatches

学习: Your circuit has one 16-bit input, and four outputs. Build this circuit that recognizes these four scancodes and asserts the correct output. To avoid creating latches, all outputs must be assigned a value in all possible conditions (See also always…

【HTML】简单制作一个3D动画效果重叠圆环

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文件名改为[index.html]&#xff0c;CSS的…

搞学术研究好用免费的学术版ChatGPT网站-学术AI

学术版ChatGPThttps://chat.uaskgpt.com/mobile/?user_sn88&channelcsdn&scenelogin 推荐一个非常适合中国本科硕士博士等学生老师使用的学术版ChatGPT&#xff0c; 对接了超大型学术模型&#xff0c;利用AI技术实现学术润色、中英文翻译&#xff0c;学术纠错&#…

centOS如何升级python

centOS下升级python版本的详细步骤 1、可利用linux自带下载工具wget下载&#xff0c;如下所示&#xff1a; 笔者安装的是最小centos系统&#xff0c;所以使用编译命令前&#xff0c;必须安装wget服务&#xff0c;读者如果安装的是界面centos系统&#xff0c;或者使用过编译工具…

在 Amazon Timestream 上通过时序数据机器学习进行预测分析

由于不断变化的需求和现代化基础设施的动态性质&#xff0c;为大型应用程序规划容量可能会非常困难。例如&#xff0c;传统的反应式方法依赖于某些 DevOps 指标&#xff08;如 CPU 和内存&#xff09;的静态阈值&#xff0c;而这些指标在这样的环境中并不足以解决问题。在这篇文…

Stable Diffusion 本地化部署

一、前言 最近在家背八股文背诵得快吐了&#xff0c;烦闷的时候&#xff0c;看到使用 AI 进行作图&#xff0c;可以使用本地话部署。刚好自己家里的电脑&#xff0c;之前买来玩暗黑4&#xff0c;配置相对来说来可以&#xff0c;就拿来试试。 此篇是按照 Github 上的 stable-d…

Android JNI基础

目录 一、JNI简介1.1 什么是JNI1.2 用途1.3 优点 二、初探JNI2.1 新建cpp\cmake2.2 build.gradle配置2.3 java层配置2.4 cmake和c 三、API详解3.1 JNI API3.1.1 数据类型3.1.2 方法 3.2 CMake脚本 四、再探JNI 一、JNI简介 1.1 什么是JNI JNI&#xff08;Java Native Interfa…