题目大意:
判断一个链表是否是回文链表
思路:
原地判断(时间复杂度为1)的解法:
1.将链表从中间二分为两个链表
2.翻转第二个链表
3.判断两个链表是否相同(可能存在第一个链表比第二个链表多一个元素,只比较长度相同的部分)
提示知识点:
链表操作:遍历、二分、反转。
代码链接:
234.palindrome-linked-list.java
题目大意:
二进制字符串数组中,不超过m个0、n个1的最大字符串子集。
思路:
定义一个二维数组dp[m+1][n+1]
遍历字符串数组
动态方程:
dp[i][j] = max(dp[i][j], dp[i - count[0]][j - count[1]] + 1),count[0]为字符串中0的个数,count[1]为字符串中1的个数。
提示知识点:
动态规划,HashTable
代码链接:
474.ones-and-zeroes.java
题目大意:
最长的有效符号对字符串长度
思路:
定义一个栈,保存括号在数组中的索引。
遍历字符串,遇到左括号,入栈索引;
遇到右括号,出栈:出栈后栈为空,则入栈索引(不匹配任何括号,仅用来计算长度);出栈后栈不为空,则计算长度,并与最大长度比较。
比如,对字符串"())()"而言,这个过程是这样的:
当前字符串 | 栈中下标 | 最大长度 |
---|---|---|
空 | -1 | 0 |
( | -1,0 | 0 |
() | -1 | 2 |
()) | 2 | 2 |
())( | 2,3 | 2 |
())() | 2 | 2 |
提示知识点:
栈
代码链接:
32.longest-valid-parentheses.java
题目大意:
设计一个环形队列。环形队列的优点是更好利用数组的空间:对于传统的队列,一旦队列满了,即使出队了元素,也无法继续插入任何元素。环形队列很好地解决了这一问题。
思路:
为了区分队列满和队列空这两种情况,需要牺牲一个数据单元,队尾指向队列中最后一个元素的下一个位置,那么队列为空时,队头指针front和队尾指针rear相等,队列满时,(rear+1)%size和front相等。
当队列为空时,读队头和队尾元素或入队出队,直接返回无效值-1。
提示知识点:
队列
代码链接:
622.design-circular-queue.java
题目大意:
对于[0-n-1]的整数序列,判断整体反转对和本地反转对的数量是否相等。
整体反转对的定义为:对于(i, j)满足
0 <= i < j < n
nums[i] > nums[j]
本地反转对的定义为:对于i满足
0 <= i < n - 1
nums[i] > nums[i + 1]
思路:
整体反转对和本地反转对的数量相同,那么不存在这样的(i,j):
nums[i]>nums[j]
j-i>=2
1.由于是[0-n-1]的序列,所以任何一个数的值与它的数组索引值的差的绝对值只能小于2.
2.如果不是[0-n-1]的序列,而是随意的序列,我们反向遍历这个数组的元素,并记录当前序列[i - n-1]的最小值,如果nums[i-2]大于这个最小值则返回false。
提示知识点:
数学
代码链接:
775.global-and-local-inversions.java
题目大意:
数组中元素的下标i和值arr[i]满足arr[i] = (2 * i) + 1。一个操作的定义为0 <= x, y < n,arr[x] -=1 且 arr[y] += 1,求使得数组中元素都相等的最小操作数。
思路:
这个题通过数学归纳法找规律:
数组长度 | 最小操作数 |
---|---|
1 | 0 |
2 | 1 |
3 | 2 |
4 | 4=1+3 |
5 | 2+4 |
6 | 9=1+3+5 |
…… | …… |
2k | k*k = (1+2+…k-1)*2+k |
2k-1 | k*(k-1)= (1+2+…k-1)*2 |
提示知识点:
数学
代码链接:
1551.minimum-operations-to-make-array-equal.java
题目大意:
字符串长度为偶数,对半二分,两部分是否相似,相似的定义是元音字母个数一样。
思路:
比较简单,统计元音字母个数
提示知识点:
字符串基本操作
代码链接:
1704.determine-if-string-halves-are-alike.java
题目大意:
给出由数字2-9构成的字符串,每个数字代表一个字母,映射关系与电话键上一致,求数字字符串对应的所有字母组合。
思路:
用Map存储数字和字母的映射关系。DFS递归遍历数字字符串,递归返回条件是当前遍历的索引等于字符串长度。dfs中循环遍历数字映射的字母字符串,每次拼接一个字母。
提示知识点:
map dfs
代码链接:
17.letter-combinations-of-a-phone-number.java
题目大意:
校验词典中单词是否按照一定顺序排序。排序规则按照给定的order字符串中字母的先后顺序。order中包含词典中所有的字母。
思路:
排序规则,对于s1和s2
1.s1和s2相同,符合,判断结束
2.s1是s2的子串,符合,判断结束;反之不符合,判断结束
3.遍历s1和s2长度重合的部分,对每个字母依次判断顺序。
提示知识点:
排序
字符串 indexOf:判断一个字符串是否是另一个字符串的子串,得到字符在字符串中的位置
代码链接:
953.verifying-an-alien-dictionary.java
题目大意:
求数组中的最长递增路径的长度
思路:
以数组中元素(i,j)为起点dfs往四个方向遍历,为了避免重复的遍历过程,再用dp数组作为缓存,表示以(i,j)为起点的最长路径长度,当再次遍历到(i,j)时直接返回缓存值。
提示知识点:
dfs dp
代码链接:
329.longest-increasing-path-in-a-matrix.java
题目大意:
求树最深叶子节点值的总和
思路:
1.递归先求出树的深度
2.递归左右子树求最深叶子节点值总和
提示知识点:
递归解树的相关问题
代码链接:
1302.deepest-leaves-sum.java
题目大意:
重新排列1-n,使得相邻元素差的绝对值恰好是k种不同的数。
思路:
首先知道:
1 2 3 …… n 相邻元素差的绝对值都为1
1 n 2 n-1 ……相邻元素差的绝对值为1,2,……n-1,n-1种不同的数
那么,要得到k种。
前n-k-1个数按照1 2 …… n-k-1排列
后面的数按照 n-k n n-k+1 n-1 ……排列
提示知识点:
数学
代码链接:
667.beautiful-arrangement-ii.java
题目大意:
嵌套列表的遍历
思路:
思路1.首先遍历嵌套列表,如果当前元素是整数,则添加到队列,如果是列表,则递归遍历当前列表。然后hasNext和next对队列进行操作。
思路2: 借助一个栈,将嵌套列表中元素反向入栈。只有当调用hasNext时,才判断元素是整数还是列表,是整数返回true,是列表则反向循环遍历列表,直到栈为空或嵌套列表中的第一个元素是整数。
提示知识点:
设计
代码链接:
341.flatten-nested-list-iterator.java
题目大意:
对于一个链表和元素x,重新划分链表使得小于x的元素位于大于等于x元素的前面。
思路:
使用两个指针保存当前最后一个小于x的节点和最后一个大于等于x的节点,还需要一个指针,保存第一个大于等于x的节点。遍历结束后,最后一个小于x的节点指向第一个大于等于x的节点。
有2种特殊的情况,不存在小于x的节点或不存在大于等于x的节点。因此需要在遍历结束重新链接时,对指针判空。
提示知识点:
链表 快速排序
代码链接:
86.partition-list.java
题目大意:
斐波拉契数列:
F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), n > 1.
给出n,求F(n)
思路:
1、借助长度为n+1的数组f
2、借助两个变量x,y
x=0,y=1
循环n次,y = x+y ,最后y的值就是f(n)
提示知识点:
代码链接:
509.fibonacci-number.java
题目大意:
循环删除字符串中连续k个相同的字符。
思路:
使用一个栈存储字符,如果有k个相同的连续字符则删除它们。
为了方便,使用Pair存储字符和它出现的次数。
提示知识点:
字符串、栈基本操作。
代码链接:
1209.remove-all-adjacent-duplicates-in-string-ii.java
题目大意:
求二维数组中和等于target的子数组个数
思路:
1.子问题是求一维数组中和等于target的子数组。借助一个map,ans += preSum.get(sum - k)
2.对于二维的情况,二维变一维,从第一行开始,依次用2,3,……n行累加,每次累加后求子数组个数。以此类推,第二行,依次用3,4,……n行累加,直到第n行。这样的顺序包含所有的情况且防止数据被覆盖。
提示知识点:
动态规划, HashMap
代码链接:
1074.number-of-submatrices-that-sum-to-target.java
题目大意:
删除链表中倒数第N个结点
思路:
1、第一次遍历出链表的长度。然后删除正向第len-n个结点。
2、双指针法。首先指针p遍历到第n个结点,然后指针q指向头结点,使用pre记录q的前驱节点,同时遍历p,q,当p遍历到最后一个节点,q就是倒数第n个结点,然后做删除操作。
需要考虑倒数第n个结点是第一个结点的特殊情况。
提示知识点:
链表基本操作。
代码链接:
19.remove-nth-node-from-end-of-list.java
题目大意:
给出一个元素不重复的数组,求组合出目标值target的种数。每个数可以用无数次。
思路:
动态规划。首先对数组nums排序,
双重循环 ,动态规划方程:
cnt[i] += cnt[i-nums[j]] , i >= nums[j],
最后cnt[target]就是所求的种数。
提示知识点:
动态规划
代码链接:
377.combination-sum-iv.java
题目大意:
N叉树的前序遍历
思路:
1、递归方式,图的深度优先遍历,比较简单
2、非递归方式,借助一个栈,当栈不为空时循环,取栈顶元素,
如果存在孩子节点则按顺序入栈一个孩子节点,添加进遍历序列,并将该孩子节点与父节点的链接关系删除。
如果不存在孩子节点(还有种情况是所有孩子节点都遍历完),则出栈。
提示知识点:
深度优先遍历
代码链接:
589.n-ary-tree-preorder-traversal.java
题目大意:
给出一个三角矩阵,计算从顶部到底部的最短路径和。
思路:
自底向上遍历矩阵。
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
triangle[0][0]即为所求
提示知识点:
动态规划
列表的基本操作
代码链接:
120.triangle.java
题目大意:
一面砖墙,划一条竖线通过最少的砖。通过砖与砖的缝隙不算通过砖。
思路:
理解题意后发现,竖线要通过缝隙最多的一列,缝隙可看作每一行砖长度累加的一个数,也就是统计所有行累加的数出现最多的次数,通过的砖数就用总行数减去这个最多的次数。注意不要统计最后一个累加的数,因为每一行总长相同。
提示知识点:
map
代码链接:
554.brick-wall.java
题目大意:
统计由0和1组成的字符串中0和1个数相同的子串个数。位置不同的子串即使内容相同也看作不同的子串。
思路:
通过例子来看,对于000111,
0001 满足的子串有1个
00011 满足的子串有2个
000111 满足的子串有3个
对于10101,
10 满足的子串有1个
101 满足的子串有2个
1010 满足的子串有3个
10101 满足的子串有4个
pre:之前连续的0或1个数 cur:当前连续的0或1个数, 当pre大于等于cur时,满足条件的子串个数加1。当i和i-1位置的字符不同时,cur赋值给pre。
提示知识点:
代码链接:
696.count-binary-substrings.java
题目大意:
求网络中的关键连接。网络中的关键连接指的是如果去除这条连接,会导致一些节点之间无法连通。
思路:
Tarjan算法。
提示知识点:
代码链接:
1192.critical-connections-in-a-network.java
题目大意:
顺时针90度旋转一个n*n矩阵
思路:
顺时针90度旋转可拆分为2个操作:
1.正对角线两侧元素互换
2.每一行元素逆转
提示知识点:
数组
代码链接:
48.rotate-image.java
题目大意:
当一个建筑物的高度小于下一个建筑物的高度时,可使用梯子或砖头。使用梯子直接到达,使用砖头个数必须为高度差。你有一些梯子和砖头,问你能到达的最远建筑物下标。
思路:
最大高度差的建筑优先选择梯子。
遍历建筑物,使用优先队列保存后一个建筑与前一个建筑的正高度差,如果队列元素个数大于梯子数,考虑用砖头。直到没有可用的梯子或砖头,结束遍历。
提示知识点:
贪心,优先队列
代码链接:
1642.furthest-building-you-can-reach.java
题目大意:
判断一个数是否是3的幂
思路:
无需循环的解法:
n的取值范围[-2^31 , 2^31 - 1],这区间最大的3的幂是1162261467(可先写一个程序算出)。如果一个数是3的幂,那么这个数必须大于0且被1162261467整除。
对数法:a = Math.log(n) / Math.log(3)
Math.abs(a - Math.rint(a)) <= 0.00000000000001
提示知识点:
数学
代码链接:
326.power-of-three.java
题目大意:
机器人从左上角走到右下角有多少种不同的路径。机器人只能向下或向右,路径中的障碍物不可穿过。
思路:
原地操作
对于obstacleGrid[i][j]=1,
obstacleGrid[i][j] = 0;
对于obstacleGrid[i][j]=0,
path[0][j] = path[0][j-1]
path[i][0] = path[i-1][0]
path[i][j] = path[i][j-1] + path[i-1][j] , i>0,j>0
提示知识点:
动态规划
代码链接:
63.unique-paths-ii.java
题目大意:
在一个递增数组中,找出一个数出现的第一个和最后一个位置。
思路:
先二分查找第一个位置,再二分查找最后一个位置。
当lo小于hi时循环
查找最后一个位置,如果当前的值大于target,则hi变为mid,否则lo为mid+1
查找第一个位置,如果当前的值大于等于target,则hi变为mid,否则lo为mid+1
最后,lo就是查找的索引值
提示知识点:
二分查找
代码链接:
34.find-first-and-last-position-of-element-in-sorted-array.java
题目大意:
给出x,y和bound三个数,求出所有不大于bound 的x^ i + y ^ j, i >= 0 且j >= 0。
思路:
两个嵌套的for循环。注意x和y为1的特殊情况,此时x和y的n次幂都是1,只需算一次,不要死循环。而且,当和sum已经大于bound时,后面的都不需判断了,跳出循环。
提示知识点:
代码链接:
970.powerful-integers.java