写在前面的话: 养成做题的好习惯。论文啊。
做题时间: 2020年3月9日~2020年3月15日
记录: 题数16道题,时间为871min。
最近更新时间: 20200315

岛屿的最大面积

链接:https://leetcode-cn.com/problems/max-area-of-island/
类名:
考察点: 图、深搜
解题过程:力扣3月每日1题
很典型的对图做深度搜索,统计每次搜索中出现的1的个数,取1的出现个数最多的值即为所求岛屿的最大面积。明白思想,图的代码还是不熟练。

找到小镇的法官

链接:https://leetcode-cn.com/problems/find-the-town-judge/
类名:
考察点: 图、数组
解题过程:
一开始被误导成图的深搜遍历,判断每次遍历的最后1个节点的值是否相等且以这个节点的值出发,没有到其他节点的路径。很尴尬。后来想了下,其实用两个数组记录每个人信任的人数量与被信任的次数,假设总人数为N,信任的人数量为0且被信任的次数为N-1(不包括自己),此时的数组下标即为所求的法官。

从字符串生成二叉树

链接:https://leetcode-cn.com/problems/construct-binary-tree-from-string/
类名:
考察点:树、递归
解题过程:没时间,保留待做。
把字符串分成根节点、左子树对应字符串与右子树对应字符串,递归生成二叉树即可。每次递归时,需要找左右子树对应子串的位置,可以在树递归遍历前,先遍历字符串,记录每个括号对应的另一半括号的位置,这样能有利于在递归时拆分字符串为根节点以及对应的左右子树的字符串。

找树左下角的值

链接:https://leetcode-cn.com/problems/find-bottom-left-tree-value/
类名:
考察点: 树、层次遍历
解题过程:
观察树左下角的值,其实就是树最后一层的最左边或者说从左到右遍历的第1个节点。
层次遍历,记录每层从左到右遍历的第1个节点即可。

二叉树最大宽度s

链接:https://leetcode-cn.com/problems/maximum-width-of-binary-tree/
类名:
考察点: 树、层次遍历、哈希表
解题过程:
通过观察,对树的每个节点标记,记根节点为1,则对应左右节点分别为2和3,即假设跟节点为n,则左右节点为2n与2n+1。遍历树两次,第1次遍历树时用哈希表记录每个节点的位置与对应的标记值,第2次遍历则为层次遍历,计算树每层节点的最左边与最右边的节点差值+1,即为该层节点的宽度,取最大值即为所求的二叉树最大宽度。

最长上升子序列

链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
类名:
考察点: 动态规划
解题过程,力扣3月每日1题
第一反应是动态规划,确定dp数组的含义,dp[i],表示以第i个元素作为结尾的最长上升子序列的最大长度;通过数学归纳法找状态转移方程,0<=i<n,0<j<i, dp[j]<dp[i]则是表示满足上升子序列的定义,dp[i]=较大值(dp[i],dp[j]+1),当前第i个位置结尾的最长上升子序列的最大长度等于该位置前形成的所有上升子序列的长度的最大值,当前位置的形成的上升子序列的长度等于前一个满足最大上升子序列的位置的值+1,1表示算上当前元素;确定基础问题是什么(dp[i]=1,当前所在位置的元素作为一个子序列)。

无向图中连通分量的数目

链接:
https://leetcode-cn.com/problems/number-of-connected-components-in-an-undirected-graph/
类名:
考察点: 图、深搜
解题过程:
图的遍历,深搜,记录形成的连通分量数目即可。需要注意单个节点也是一个连通分量。

子树的最大平均值

链接:https://leetcode-cn.com/problems/maximum-average-subtree/
类名:
考察点: 树、递归
解题过程:
这类题做多了就知道其实就是树的递归遍历变形,每次递归时记录当前节点的个数、和与平均值,取最大平均值即可。

多数元素

链接:https://leetcode-cn.com/problems/majority-element/
类名:
考察点: 数组、哈希表
解题过程:力扣3月每日1题
第1反应就用哈希表记录下每个元素的个数,元素个数超过数组长度的一半,这样的空间复杂度为o(n),即为所求元素。然后又想了下,既然该元素的各处超过数组长度的一半,假设所求元素代表1,其他元素代表-1,那么1的个数肯定大于等于1。那么好整了,使用两个变量,变量1记录元素的个数,变量2记录当前元素的值,遍历整个数组,与变量2的值相等则递增变量1,否则递减变量1。最后记录的变量2就是所求的元素。

最小覆盖子串

链接:https://leetcode-cn.com/problems/minimum-window-substring/
类名:
考察点: 滑动窗口
解题过程:
看师妹最近提滑动窗口次数特别多,记录学习下。在字串问题时用滑动窗口,理解题意后套解题模板还是很舒服的。这道题目的意思是存在字符串1与字符串2两个字符串,需要在字符串1中找出包括字符串2中所有字符的最小字串。滑动窗口的思路是这样的,第1,遍历字符串2,记录每个字符出现的个数(哈希表1),接着对字符串2,取两个指针left与right,从字符串2顺序遍历,left与right这个闭区间(包含起始位置)就是一个窗口;第2步,改变指针right的位置,扩大这区间包含的数,并记录这个区间中出现在字符串1中的字符个数(记作哈希表2),当这个区间中哈希表2记录的字符类型且每种字符个数大于等于哈希表1中记录的个数时,停止改变right;第3步,此时[left,right]这个区间已经包含了字符串1中字符类型且每种字符类型个数也符合要求,开始改变指针left的位置,直到哈希表2中记录的字符串1中任意字符的个数比哈希表1中记录的对应字符个数少时,停止改变left,此时我们找到了第1处符合题目要求的[left,right]区间。第4步,重复第2步与第3的过程,直到遍历完整个字符串2。

int left,int right;
while(right<字符串2的长度){
窗口添加元素;
right++;
while(符合条件){
窗口移除元素
left++;
}
}

我用java实现上述思想时,整了一个多小时没通过,检查自己的思路也没问题。单步调试才发现,是下面代码的问题,直接在if语句中从哈希表中取数据进行比较,而不是用临时变量来保存数据后再比较,当数据太大时,力扣平台就不通过我写的代码了,尴尬。

int n0 = winMp.get(temp);//窗口中记录的字符个数
int n1 = mp.get(temp);//最终结果中记录的字符个数
//if(winMp.get(temp)==mp.get(temp)) {//错误
if(n0==n1){//正确
winCharNum++;
}

字符串的最大公因子

链接:https://leetcode-cn.com/problems/greatest-common-divisor-of-strings/
类名:
考察点: 辗转相除法
解题过程:力扣3月每日1题
万万那没想到最后是用辗转相除法搞定的,一开始往这上面思考,没想出个所以然就放弃了。尝试暴力、找子串啥的。最后实在受不了,看下题解,结果发现智商被碾压。重新分析这道题目。先考虑边界条件,对于字符串1与字符串2,当两者任意一个为空时,返回空字符串;当字符串1+字符串2与字符串2+字符串1不相等时,也找不到一个重复子串,因此返回空字符串;接着就开始考虑一般情况。先整出正常的最大公约数的写法

gcd(int a,int b){
if(b==0) return a;
else{ return gcd(b,a%b)};
}}

假设所求字符串的最大公因子子串的长度为x,假设存在这样的子串,则字符串1经过m次变化,字符串2经过n次变化,m乘以x等于字符串1的长度,n乘以x等于字符串2的长度,因此要求的子串最大的长度值即x的最大长度值就是字符串1的长度与字符串2的长度的最大公约数。然后,就没然后了。我的智商被碾压了。告辞。

统计同值子树

链接:https://leetcode-cn.com/problems/count-univalue-subtrees/
类名:
考察点: 树、递归
解题过程:
这题目描述的真是简单,模糊的子树概念。所谓的同值子树有两种情况,1是指叶子节点;2是指二叉树所有的节点(根节点、左右子树节点)的值都是同一个。以当前遍历节点为同值子树的左右子树同样应该是同值子树,所以用递归遍历树,遍历的当前节点为空时则返回真,此时不计数,否则递归判断当前节点的左右子树和判断当前节点与左右子节点是否都相等,若上述条件都满足则为同值子树,计数加1,否则以当前节点为根节点的子树不是同值子树。

将数组分成和相等的三个部分

链接:https://leetcode-cn.com/problems/partition-array-into-three-parts-with-equal-sum/
类名:
考察点:数组、双指针
解题过程:力扣3月每日1题
看到这题后,第一直觉就是看和是不是3的倍数,数组所有元素的和不是3的倍数则一定不符合题目要求的数组,接着考虑,既然是三部分,会有两个起始的位置begin或者end,这不就是符合双指针的套路,开始从这个点考虑。对于数组和为3的倍数,可以得出每部分需要凑出的值应该为数组和/3,那么可以通过起始位置begin或者end算出第1部分和第3部分的和,看是不是凑出的值,是的话,则不对该部分做求和操作,否则则对该部分做求和操作,同时改变两个指针的值。
那么什么时候跳出循环,第1部分和第3部分的值都为需要凑出的值,就返回真,否则当begin+1>=end的时候结束循环。我最开始考虑的是begin<=end结束循环,代码并不通过。我们假设一个数组能分成和相等的三部分话,那么第2部分或者说中间部分一定至少存在1个值,所以第1部分的结束位置与第3部分的开始位置end,应该满足的关系是begin+1<end,所以begin+1>=end的时候,循环就结束了。

全排列II

链接:https://leetcode-cn.com/problems/permutations-ii/
类名:
考察点: 回溯、减枝
解题过程:
与力扣的另一道题基本思想是一致的,只是这道题是存在重复元素。回溯算法基本框架+剪枝。先排序使得重复元素相邻,目的是为了剪枝方便,考虑的情况要少些,然后画出回溯过程形成的树结构,找到剪枝的条件(当前元素与上一个元素相等且上一个元素未被遍历)。套算法模板,搞定。

二叉树的直径

链接:https://leetcode-cn.com/problems/diameter-of-binary-tree/
类名:
考察点: 树、递归
解题过程:力扣3月每日1题
类似于树的高度题目变形。遍历每个节点,记录每个节点的左右子树高度,求每个节点的左右子树高度和,最大的高度和即为所求二叉树的直径。刚开始想成最左节点到最右节点经过的边长,想偏了。

二叉树的完全性检验

链接:https://leetcode-cn.com/problems/check-completeness-of-a-binary-tree/
类名:
考察点:树、层次遍历、完全二叉树
解题过程:
刚开始考虑用递归计算节点对应左右子树的高度和左右节点是否存在来判断完全二叉树,然后考虑各种特殊情况,整个人都被搞糊涂了。就放弃递归,用迭代实现树的层次遍历,考虑到完全二叉树最后一个层次遍历的节点要么存在左子树,要么左右子树均为空,标记满足这类特性的节点,再继续遍历二叉树,若遍历的节点的左右子树不都为空,则该子树不为完全二叉树,否则即为完全二叉树。我真蠢,一开始就应该从完全二叉树的特点出发。

买卖股票的最佳时机

链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
类名:
考察点: 动态规划
解题过程:力扣3月每日1题
动态规划问题。找状态,确定dp数组的意义,找状态转移方程。
n天,0<=i<n,交易次数为k,dp[i][k][0]表示i天拥有股票的最大值,最多交易次数为k;dp[i][k][1]表示i天没有股票的最大值,最多交易次数为k。
dp[i][k][0] = 最大值(dp[i-1][k][0],dp[i][k][1]+第i天的股票),第i天没有股票,情形1:今天本来就没有股票,和昨天i-1也没有股票,保持一致;情形2:今天有股票,卖了当天的股票(加表示卖股票赚)。
dp[i][k][1] = 最大值(dp[i-1][k][1],dp[i][k-1][0]-第i天的股票),第i天有股票,情形1:今天有股票,但不买入股票,和昨天一致;情形2:今天没有股票,昨天i-1也没有股票,买了当天的股票(减表示买股票花钱)。而k-1则表示交易次数需要较少1次。
交易次数k为1,所以下列可化简,
dp[i][1][0] = 最大值(dp[i-1][1][0],dp[i][1][1]+第i天的股票)
dp[i][1][1] = 最大值(dp[i-1][1][1],dp[i][0][0]-第i天的股票)//交易次数为0,dp[i][0][0]=0
变成了
dp[i][0] = 最大值(dp[i-1][0],dp[i][1]+第i天的股票)
dp[i][1] = 最大值(dp[i-1][1],-第i天的股票)//交易次数为0,dp[i][0][0]=0