自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(40)
  • 收藏
  • 关注

原创 LeetCode162. 寻找峰值

题目说了,峰值元素就是大于相邻左右元素的元素,又说了nums[-1] = nums[n] = -∞,所以我们就寻思着,如果nums[0]比nums[1]大,再加上nums[-1]是负无穷,那么nums[0]不就是一个峰值元素了吗。如果nums[0]不比nums[1]大,那么我们接着把nums[1]和nums[2]比就好了,如果nums[1]大,也可以认为nums[1]是峰值元素。如果nums[1]不比nums[2]大,就继续往后找。这种做法时间复杂度是O(n).class Solution {pu.

2020-07-31 22:14:33 79

原创 LeetCode160. 相交链表

这题做法比较贼,让两个指针p, q分别指向两个链表的头,然后只要两个指针不为空且指向的位置不同,就都向后移动,当一个指针为空的时候,就指向另一个链表的头。比如上面这图,假设相交部分之前,两个链表的长度分别是a,b,相交链表之后的长度为c。那么p指针走了a + c长度(走完第一个链表)之后,指向第二个链表头headB;q指针走了b + c长度(走完第二个链表)之后,指向第一个链表头headA。然后两个指针又分别走了b和a的长度,最终,在经过a + b + c之后,两个指针终于相遇了。这是两个链..

2020-07-31 21:40:11 100

原创 LeetCode155. 最小栈

要能够在常数时间内检索到栈内最小元素,我们可以额外开一个栈,这个额外的栈的栈顶元素存放目前栈内的最小元素,每次栈内压入一个新元素,辅助栈也压入一个元素,也就是把新元素和原栈顶元素比较,较小的那个就是新的最小元素,压入辅助栈的栈顶;原栈弹出栈顶元素的时候,辅助栈也弹出栈顶元素,这样,不管什么时候,辅助栈的栈顶元素总是存放原栈当前的栈内最小元素。题目说了,push、pop和getMin操作总是在非空栈上调用,所以不需要做特判。不过,由于辅助栈每次压入的元素都是新元素和原栈顶元素的最小值,这样,当压入第一个.

2020-07-31 21:22:30 65

原创 LeetCode154. 寻找旋转排序数组中的最小值 II

经过旋转后的数组,满足这样一个性质,最小值右边的元素,都大于等于最小值(因为这题有重复元素,所以有可能等于),最小值左边的元素,都大于等于最小值。所以每一次二分,我们可以与当前区间的最左边或最右边进行比较,确定最小值的位置。这里我们每次将区间中点的值nums[mid]与区间右端点nums[right]进行比较。如果nums[mid] < nums[right],这说明区间右半部分是升序的,那么最小值肯定不在这部分,最小值最大只能是nums[mid],所以让right = mid;如果.

2020-07-31 21:05:54 153

原创 LeetCode153. 寻找旋转排序数组中的最小值

题目说了是对升序的数组做旋转得到的数组,可以考虑二分。因为做过旋转了,所以不能直接用二分。找一下规律,旋转数组原来是升序的,那么最小的元素就是旋转前的第一个元素。旋转之后,相当于把原来升序数组的前面某些部分放到了数组的后面,那么这个数组就满足,在最小的元素之前的部分数组依旧是升序的,然后最小的元素到数组结尾的部分也是升序的。最小值的前一个元素一定比它大。所以我们需要找到数组“旋转"的位置。这个旋转位置可以用二分查找,比如说(当前搜索区间的)前半部分,如果nums[mid] > nums[l.

2020-07-30 11:21:40 204

原创 LeetCode152. 乘积最大子数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kxpMuZ2O-1596077117716)(https://img2020.cnblogs.com/blog/2078361/202007/2078361-20200730103606608-318728054.png)]要求乘积最大的子数组(子数组一定都是连续的),可以暴力枚举子数组起点和终点,求和。但是肯定超时。如果用动态规划,则只需要一遍扫描就可以得出结果。可以用maxProduct[i]表示以i结尾的最大的子数组

2020-07-30 10:45:34 97

原创 LeetCode151. 翻转字符串里的单词

题意是要把原字符串中所有的单词划分出来,倒序用一个空格的间隙来连接字符串,我们只需要划分出所有的单词,然后把它们连接起来,每两个单词之间放一个空格就好了。分割空格之间的单词,很容易想到用双指针进行分割,只需要找到每个单词的第一个字母(也就是第一个不为空格的字母),然后左指针指向这个单词,右指针不断右移直到碰到指向一个空格或者字符串的末尾。我们额外开一个字符串数组words存放所有划分出来的单词,把每一个划分出来的单词都存在这个数组里,分割出所有的单词之后,翻转一下这个数组,然后把所有单词连接起来(每两.

2020-07-30 10:24:04 104

原创 LeetCode第31场双周赛题解

1523. 在区间范围内统计奇数数目先计算从low到high一共有多少个数: int diff = high - low + 1;找规律发现,如果low和high都是奇数,那么奇数个数就是diff上取整,其他情况奇数数目都是diff下取整。class Solution {public: int countOdds(int low, int high) { int diff = high - low + 1; if(low % 2 == 1 &&amp

2020-07-28 19:05:04 130

原创 LeetCode91. 解码方法

经典dp问题,用dp[i]表示前i个字符解码方案的总数。显然dp[0]=1(空字符也相当于一种解码方案),然后从小到大递推计算dp数组,如果当前当前数字不是0(也就是大于等于1小于等于9),则当前字符可以连接在之前所有字符之后成为一个新方案。当前字符是0是不行的,0不能映射成英文字母。所以有:if('1' <= s[i] && s[i] <= '9') { dp[i] = dp[i - 1];}不过还是有一种情况,就是当前字符和前一个字符的结合com.

2020-07-18 12:20:10 88

原创 LeetCode90. 子集 II

DFS枚举所有子集,对于每个数字,假设出现次数是cnt,则枚举这个数字的出现次数0,1, 2,…cnt,其他数字同理。所以解空间是指数级的。要计算所有数字出现的次数,可以直接排序,这样同样的数字都是相邻的。然后一个for循环枚举每个数的添加次数,假设一个数字的出现次数是cnt,则枚举它的出现次数为0, 1, 2,…cnt。之后不要忘了恢复现场。最后两个for循环咋一看难以理解,画一下函数调用关系就明白了。class Solution {public: vector<vector.

2020-07-18 11:02:22 74

原创 LeetCode89. 格雷编码

找规律,格雷码的一种生成方法如下图。对于n先将n-1的所有格雷码复制一下,然后轴对称所有n-1的格雷码,然后前半部分补0,后半部分补1,就得到了n的格雷码。class Solution {public: vector<int> grayCode(int n) { vector<int> res(1, 0); while(n--) { //经过n次复制+轴对称+补0补1操作,得到.

2020-07-18 00:19:29 102

原创 LeetCode88. 合并两个有序数组

归并两个已排序数组为一个数组,不同于归并排序的归并用一个额外的数组,这里在第一个数组预留出足够的空间,所以需要直接在第一个数组里存放原来的两个数组的所有元素。归并排序里,是额外开一个数组,然后两个指针分别从第一个数组和第二个数组的开头进行比较,比较小的那一个元素加入新数组中,然后某个数组为空之后,把另一个数组剩下的所有元素加入到新数组中。这个过程结束之后,新数组就是归并之后的两个数组。不过在这题里,从头开始比较两个数组,然后再把元素放入nums1里,会覆盖nums1原本的元素,不可行。正好nums.

2020-07-17 23:48:25 113

原创 LeetCode87. 扰乱字符串

判断S2是否是S1的扰乱字符串。根据题目的定义,S1如果经过若干次对于部分子串的翻转操作能够得到S2,则S2是S1的扰乱字符串。首先,如果S2是S1的扰乱字符串,那么S1中每个字符的出现次数必然和S2中每个字符的出现次数一致,也就是说,我们用两个字符串S3、S4备份一下S1和S2,对S3和S4排序之后,S3和S4必然是相等的情况下S2才有可能是S1的扰乱字符串,否则返回false。然后就是要判断S2是否能经过S1的若干次操作得到了。这里就是要枚举S1所有可能得到的扰乱字符串,判断是否有和S2相等的..

2020-07-17 22:57:27 112

原创 LeetCode86. 分隔链表

要根据链表节点的值是否大于等于x将链表划分为两段,首先需要链表中大于等于x和小于x的节点的个数,所以无法直接在原链表上做修改。既然要分开大于等于x的值和小于x的值,我们可以考虑开两个链表,这样按顺序扫描原链表的时候,小于x的值接到第一个链表,大于等于x的值接到第二个链表。然后再把这两个链表连接起来,就得到了满足题目条件的链表,且节点之间的相对顺序没变。由于链表里可能一个大于等于x或者小于x的值都不存在,所以开的两个链表是有可能为空的,因此我们需要引入虚拟头节点。不妨设两个链表的虚拟头节点为left.

2020-07-17 21:41:40 122

原创 LeetCode85. 最大矩形

这题其实是84题的进阶版。要求最大矩形,同样也是枚举所有矩形,关键就在于如何枚举。如果直接枚举所有起点和终点,复杂度最起码是O(n^4),超时。所以要换种方式枚举,可以考虑固定住所有矩形的底边,比如以每一行作为底边,枚举以这个底边,往上有哪些矩形,分别计算面积。固定住底边之后,网上所有的连续的’1’就构成了类似84题的柱状图,84题我们已经用单调栈在O(n)时间内解决了,枚举所有底边(行数)也需要O(n),所以总的时间复杂度是O(n^2)。因为原数组是字符数组,所以我们要预处理一下高度,额外.

2020-07-17 11:59:39 219

原创 LeetCode84. 柱状图中最大的矩形

要求能勾勒出来的矩形的最大高度,很自然的想法就是枚举所有矩形的宽度和高度,再通过高度和宽度的乘积求出所有矩形的面积,这样就可以知道最大矩形的面积了。暴力做法是,枚举所有矩形的宽度(也就是枚举左边界和右边界),再求出左边界和右边界内柱子的最小高度(瓶颈高度),然后得到矩形的面积。代码如下:class Solution {public: int largestRectangleArea(vector<int>& heights) { int size = ..

2020-07-17 11:02:50 124

原创 单调栈

原题链接这道题就是单调栈最经典的应用,单调栈往往就是求一个数组中每个元素左边(之前)的元素中离它最近的比它小的元素。首先很容易想到暴力做法,对于每一个元素,从当前元素的前一个元素开始往前遍历,第一个满足小于当前元素的元素就是答案,遍历完数组都不存在元素比当前元素小,则输出-1.代码如下:#include<bits/stdc++.h>using namespace std;const int N = 1e5 + 5;int a[N];int main() { int .

2020-07-16 19:54:35 100

原创 数组模拟队列

原题链接数组模拟队列和数组模拟栈其实很类似,都是用一个数组来存储元素,用指针表示当前可以操作的位置。区别就是栈只能在栈顶进行操作,所以只需要有一个top指针指向栈顶。而队列可以在队头和队尾都进行操作(出队、入队),所以需要两个指针head和tail指向队头和队尾。如果有元素入队,则tail加一,指向新元素。如果要出队,则head加一,指向原来队列的第二个元素,这个元素就是现在的对头。具体代码如下:#include<bits/stdc++.h>using namespace s..

2020-07-16 13:39:37 96

原创 数组模拟栈

原题链接题意是用数组模拟一个栈,支持四种栈操作:在栈顶插入元素,弹出栈顶元素,查询栈顶元素,查询栈是否为空。用数组模拟栈只需要开一个数组存储栈元素,再用一个额外的变量top表示当前栈顶元素下标。直接看代码吧:#include<bits/stdc++.h>using namespace std;const int N = 1e5 + 5;int stk[N], top; //栈数组和栈顶下标void init() { top = 0; ..

2020-07-16 13:26:08 122

原创 数组实现双链表

之前写了数组实现单链表,提到了数组实现链表比指针实现最大的优点就是快,可以随机存取,而且不用new节点。在图论的题目里用到邻接表,往往都是用数组实现。数组实现双链表比单链表就多了一些对于左指针的操作。为了实现的方便,不像在单链表实现里用一个额外的变量head去记录链表的头节点。而是直接用两个哨兵节点固定为双链表的头节点和尾节点。我们可以固定头节点为0,尾节点为1.也就是说,0的right指针指向链表的第一个节点,1的left指针指向链表的第一个节点。这样,0和1就被固定为头节点和尾节点了。我们

2020-07-16 13:13:12 740

原创 数组实现单链表

单链表常见的实现方法有两种,一种方式是定义一个结构体表示链表节点。比如:struct node{ int val; node* next;};然后就是通过next指针将链表的所有节点连接起来。如果涉及到链表节点的插入和删除操作,则只需要修改链表节点的指针即可。这种方式有个明显的缺点,就是不能随机存取。如果要在某个节点之后插入或者删除节点,复杂度是O(n),因为要从头开始逐个遍历到需要插入或者删除的节点(通过next指针找)。所以用结构体实现的单链表缺点就是太慢了。当然还有一

2020-07-15 20:33:48 1596 1

原创 LeetCode第 30 场双周赛题解

5177. 转变日期格式思路:按照空格划分出年月日,年已经是数字形式,不需要做处理。月是英文单词的缩写,需要对应到相应的数字。对于日,只需要把结尾的英文序数词去掉,只留下数字即可。 这里要注意月和日可能是个位数,这种情况下要在前面补一个0.class Solution {string months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};public:

2020-07-13 11:01:39 279

原创 链表题目一道

原题链接来源:剑指offer, Hulu面试题题意很简单。给定一个单链表,反转这个单链表,返回翻转后的头节点。方法一 借助栈的性质要将链表翻转,很容易想到借助栈的后进先出的性质来改变链表的顺序。将链表节点顺序压入栈中,链表节点全部进栈以后,取栈顶元素作为新链表的头节点,然后将元素不断出栈,每出栈一个元素就连接到新链表的末尾。时间复杂度:将链表元素压入栈中需要遍历一次链表,将栈中所有元素连接起来需要遍历一遍栈,时间复杂度是O(n).空间复杂度:需要额外开一个栈存放所有元素,空间复杂度是O(n).

2020-07-10 11:11:40 369 2

原创 LeetCode面试题 16.11. 跳水板

暴力枚举即可,注意特判k为0的情况。class Solution {public: vector<int> divingBoard(int shorter, int longer, int k) { if(k == 0) { return {}; } vector<int> res; set<int> hashTable; int currentLengt.

2020-07-08 00:33:32 171

原创 LeetCode83. 删除排序链表中的重复元素

判断当前节点currentNode的值和它的next指针所指向的节点的值是否相等,如果相等,就一直向后移动next指针直到遇到next指针所指节点的值和currentNode的值不相等,这时将currentNode的next指针指向这个不相等的节点即可。当currentNode和currentNode的next指针都为空时退出while循环,表示扫描链表结束(currentNode为空表示链表末尾已经指向NULL)。class Solution {public: ListNode* del.

2020-07-06 17:44:55 74

原创 LeetCode82. 删除排序链表中的重复元素 II

题意是要删除一个排序链表里所有重复出现的数字,链表里留下的数字都是只出现一次的数字。思路:用两个指针currentNode和nextNode扫描一遍有序链表,最开始初始化currentNode为链表的附加头节点dummy,nextNode为currentNode的下一个节点,然后不断判断nextNode当前所指的节点的数的个数。判断的方式是将nextNode移动到第一个和currentNode -> next所指节点的值不相等的节点,然后判断currentNode -> next的ne.

2020-07-06 11:57:55 91

原创 LeetCode81. 搜索旋转排序数组 II

方法一 先排序后二分要判断数组里是否存在target,可以先对数组排序,然后直接二分查找。这样时间复杂度是O(nlogn)。class Solution {public: bool search(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); int left = 0, right = nums.size() - 1; while(left .

2020-07-06 11:11:34 105

原创 LeetCode52. N皇后 II

这题和LeetCode第51题做法一样,只不过不是记录具体方案,而是个数。分析见第51题。代码如下:class Solution {int res = 0;int n;vector<string> path;vector<bool> cols, diagram, anti_diagram;public: int totalNQueens(int _n) { n = _n; path = vector<string>(.

2020-07-05 23:43:08 75

原创 LeetCode51. N皇后

题意是给定一个N × N大小的棋盘,求不同的N皇后方案的个数。N皇后的方案指,N个皇后放在棋盘上,互相不能攻击到。国际象棋里,皇后可以横竖斜走若干步,所以一个方案是合法的,必须满足任意一个皇后所在的行、列、对角线、斜对角线都没有其他皇后。我们要求的就是这样的方案的个数。由于每行只能放一个皇后,所以我们可以按照行来搜索方案(当然按列或者对角线/斜对角线也可,不过按行来搜索代码比较好写),要满足互相不攻击的条件,我们在搜索每一行的时候,都需要枚举这一行可以放皇后的位置,可以放皇后的条件就是:当前位置.

2020-07-05 23:42:43 111

原创 LeetCode51. N皇后

题意是给定一个N × N大小的棋盘,求不同的N皇后方案的个数。N皇后的方案指,N个皇后放在棋盘上,互相不能攻击到。国际象棋里,皇后可以横竖斜走若干步,所以一个方案是合法的,必须满足任意一个皇后所在的行、列、对角线、斜对角线都没有其他皇后。我们要求的就是这样的方案的个数。由于每行只能放一个皇后,所以我们可以按照行来搜索方案(当然按列或者对角线/斜对角线也可,不过按行来搜索代码比较好写),要满足互相不攻击的条件,我们在搜索每一行的时候,都需要枚举这一行可以放皇后的位置,可以放皇后的条件就是:当前位置.

2020-07-05 23:18:05 116

原创 LeetCode80. 删除排序数组中的重复项 II

题意是给定一个已排序数组,我们需要原地修改数组,使得相同元素最多留下2个,并且返回新的数组的大小。这题还是双指针做法,最开始左右指针都在0位置,左指针表示新的已排序数组的末尾元素位置,右指针从左向右遍历逐个判断元素是否可以加入“新数组”中。由于相同元素最多只能留两个,且数组是已排序的,所以对于一个新元素num,我们只需判断它和左指针所指元素以及左指针前一个位置的元素是否相等,如果都相等,说明这个元素以及出现两次了,所以右指针元素是无效的。只要有一个元素和右指针所指不等,说明右指针所指元素是有效的.

2020-07-05 02:33:11 139

原创 LeetCode79. 单词搜索

又是一道DFS回溯,枚举二维字符数组的所有字符作为起点,判断以这个字符作为起点DFS是否能得到word,可以就返回true,如果所有起点都不行就返回false。DFS函数就按照方向进行搜索,上下左右是个方向分别去搜,返回的情况有:1. 某方向下一个字符和word的下一个字符不相等,回溯,返回false2. 已经搜索到了最后一个位置,返回true如果某方向下一个字符越界或者已经被访问过了(即已经出现在当前从起点开始到现在的字符串中),则跳过(字符串不能包含相同位置的元素)直接看代码吧:clas.

2020-07-05 02:11:45 225

原创 LeetCode78. 子集

方法一(DFS回溯)求出所有可能的子集,就是要遍历一遍DFS递归树,把所有子集全都压入结果数组中。class Solution {vector<vector<int>> res;vector<int> onePath; //onePath是递归树的一条路径(一个子集)public: vector<vector<int>> subsets(vector<int>& .

2020-07-05 01:06:35 98

原创 LeetCode77. 组合

DFS回溯,从左至右选数,加入一个一维数组oneCombination中,当oneCombination的大小等于k,表示已经选了k个数,将oneCombination压入结果数组res中。DFS的函数签名可以写为void DFS(int n, int k, int startPos, vector& oneCombination, vector<vector>& res)表示从1~n里选k个数,当前组合的起始位置为startPos,当前组合记录在一维数组oneCombi.

2020-07-05 00:03:00 80

原创 LeetCode76. 最小覆盖子串

滑动窗口(双指针)要在字符串S里找出包含字符串T的所有字符的最小子串(注意只需要包含字符串T的所有字符),不需要子串就是T。所以我们可以扫描一遍字符串S,找出一个满足条件包含字符串T的所有字符串子串,然后根据长度是否比之前记录的字符串长度小,更新最小子串。扫描字符串S需要用到滑动窗口(双指针),指针j表示子串的起始位置,子串i表示字符串的结束位置。由于需要计算字符的出现次数,所以考虑用哈希表。开两个<char, int>型哈希表hashT和hashWindow,hashT表示字符串中.

2020-07-04 23:24:55 155

原创 LeetCode75. 颜色分类

这道题的题意是,给出一个一维数组,数组中的元素只可能是0,1,2,分别表示红色、白色和蓝色。我们需要做一个排序,使得0全部在数组前面,1在中间,2在后面。 (不过不能用sort函数)方法一(常数空间,非一趟扫描)可以用三个变量分别记录红色、白色和蓝色的出现次数,然后根据出现的次数,修改数组即可。class Solution {public: void sortColors(vector<int>& nums) { vector<int> c.

2020-07-04 22:52:15 107

原创 LeetCode74. 搜索二维矩阵

这道题是要我们在一个二维数组里搜索某个元素target,找到了返回true,没找到返回false。这个二维数组性质是,每一行都是升序的,且每一行的最后一个元素小于下一行的第一个元素。都说升序和查找了,显然应该想到二分。这题我最开始先按行二分,确定target(如果在数组里)所在的行,再对这一行做二分确定target所在的列,但是TLE了,就不贴出代码了。可以发现,这个二维数组,如果我们能把它变成一维数组,不就是一个升序的一维数组了吗?那这题不就是裸的二分了吗?可以开一个额外的一维数组顺序存放二维.

2020-07-04 22:05:13 229

原创 LeetCode73. 矩阵置零

解法一(使用O(mn)空间)可以开一个额外的二维数组,记录每个位置的元素是否已被访问过。然后我们遍历原来的二维数组,只要没被访问过且元素为0,那么就将该元素所在的行和列的元素值置为0,并且将这一行的所有元素都设置为已经访问过,以免之后的遍历碰到被置为0的元素也将那一行那一列的元素置为0.这里要注意,对于一个为0且未被访问的元素所在的行和列的元素置0的时候,要跳过本来就为0的元素,因为可能之后的遍历到了其他的本来就为0的元素,由于置了那个元素的状态为访问过,就会跳过这个元素,导致没有将那个元素所在.

2020-07-04 21:23:38 220

原创 LeetCode72. 编辑距离

考虑用一个二维dp数组表示所需的最小操作次数。dp[i][j]表示将word1的前i个字符转换为word2的前j个字符所需要的最少操作次数。由于操作的顺序对于最后操作的结果没有影响,所以我们假设操作总是从word1的前面字符操作到word1的后面字符。如果word1的第i个字符等于word2的第j个字符,所以对于第i个字符实际上是没有操作的,那么编辑距离就取决于word1的1 ~ i - 1的字符和word2的1 ~ j - 1的字符,所以我们得到: dp[i][j] = dp[i - 1].

2020-07-04 19:52:28 125

原创 LeetCode71. 简化路径

这题是要实现Linux里的类似pwd命令的功能,给出一串绝对地址,绝对地址里每两个"/"之间可能含有".","..","",/等,这些特殊情况都需要判断。思路是,遍历path字符串,对于每两个"/“之间的字符串temp,根据字符串内容考虑是否要压入一个额外的string数组strs中。strs中元素的顺序就是最终路径的各个目录的顺序,只需要用”/"把所有目录(或者说是文件名)连接起来即可。如果temp是"“或者”."("."在Linux中表示当前目录),则跳过,不需要压入strs数组中。..

2020-07-03 22:40:19 177

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除