[TOC]
mid
3.无重复字符的最长子串
1 | set+双指针i,j 当j不包含时候,添加并计算max,否则,左边界右移动 |
15.三数之和
排序,for里面套一个双指针while,注意去重
1 | while() |
146.LRU缓存
1 | 一个HashMap<Integer,Node> map |
103.二叉树的锯齿形层序遍历
1 | list.add(0,node.val) |
215. 数组中的第K个最大元素
1 | 快排 |
105.从前序与中序遍历序列构造二叉树
1 | while(preorder[ps]!=inorder[is+index]) index++; |
199. 二叉树的右视图
1 | if(i==size-1) res.add(node.val); |
54. 螺旋矩阵
1 | while (l <= r && u <= d){ |
33. 搜索旋转排序数组
1 | if(nums[mid]<nums[right]) |
236. 二叉树的最近公共祖先
1 | if(left!=null && right==null) |
31. 下一个排列
从后往前找
1 | [1,1,5] |
1 | while(i>=0 && nums[i]>=nums[i+1]) |
排序奇升偶降链表
按奇偶位置拆分链表,得1->3->5->7->NULL和8->6->4->2->NULL
反转偶链表,得1->3->5->7->NULL和2->4->6->8->NULL
合并两个有序链表,得1->2->3->4->5->6->7->8->NULL
24. 两两交换链表中的节点
1 | ListNode next = head.next; |
98. 验证二叉搜索树
1 | return validate(root, Long.MIN_VALUE, Long.MAX_VALUE); |
958. 二叉树的完全性检验
广度进行遍历,设一个前驱指针prev,判断prev==null && node!=null
1 | if (prev == null && node != null) |
79. 单词搜索
回溯
1 | (char[][] board,int n,int m,int i,int j,char[] cs,int index) |
143. 重排链表
给定一个单链表 L:L0→L1→…→L**n-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→L**n-2→…
快慢指针找中点,反转,链表合并
1 | ListNode slow=head,fast=head.next; |
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
1 | for (int start = i; start < candidates.length; start++) |
518. 零钱兑换 II
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
示例 1:
输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
1 | int dp[][] = new int[n+1][amount+1]; |
162. 寻找峰值
峰值元素是指其值大于左右相邻值的元素。
1 | if(nums[mid]>=nums[mid+1]) |
56. 合并区间
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
1 | int left=intervals[i][0]; |
148. 排序链表
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
- 你可以在
O(n log n)
时间复杂度和常数级空间复杂度下,对链表进行排序吗?
快慢指针找中心点
归并排序
1 | ListNode l1=mergeSort(head); |
135. 分发糖果
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
1 | public int candy(int[] ratings) { |
470. 用 Rand7() 实现 Rand10()
(rand_X() - 1) × Y + rand_Y() ==> 可以等概率的生成[1, X * Y]范围的随机数
即实现了 rand_XY()
1 | while(true) { |
662. 二叉树最大宽度
1 | HashMap<Node,Integer> |
木头切割问题
给定长度为n的数组,每个元素代表一个木头的长度,木头可以任意截断,从这堆木头中截出至少k个相同长度为m的木块。已知k,求max(m)。
输入两行,第一行n, k,第二行为数组序列。输出最大值。
暴力
1 | while (1 <= maxV) |
二分
1 | #include <iostream> |
圆环回原点问题
走n步到0的方案数=走n-1步到1的方案数+走n-1步到9的方案数。
因此,若设dp[i][j]为从0点出发走i步到j点的方案数,则递推式为:
ps:公式之所以取余是因为j-1或j+1可能会超过圆环0~9的范围
1 | public static void main(String[] args) { |
322. 零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
1 | 输入:coins = [1, 2, 5], amount = 11 |
1 | for(int i=1;i<amount+1;i++) |
739. 每日温度
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
先全部压入栈里面,不行就弹出来
1 | while(!stack.isEmpty() && T[stack.peek()]<T[i]) |
151. 翻转字符串里的单词
双指针整体反转+局部反转+去除空格
1 | while(r<=cs.length) |
670. 最大交换
先排序,然后设置diff,从后向前找到第一个不相等
1 | if (oldNum[i] != orderNum[orderNum.length - 1 - i]) |
91. 解码方法
一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,”111” 可以将 “1” 中的每个 “1” 映射为 “A” ,从而得到 “AAA” ,或者可以将 “11” 和 “1”(分别为 “K” 和 “A” )映射为 “KA” 。注意,”06” 不能映射为 “F” ,因为 “6” 和 “06” 不同。
示例 1:
1 | 输入:s = "12" |
1 | int[] dp=new int[length+1]; |
134. 加油站
输入:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
如果剩余量小于0,比如要前面的都失败
1 | run+=(gas[i]-cost[i]); |
138. 复制带随机指针的链表
三次O(n)
第一次新增节点
第二次随即指针
第三次拆分
注意拆分最后一步 cur.next=null;
36进制加法
1 | char getChar(int n) |
221. 最大正方形
1 | dp[i][j] = 1 + Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])); |
93. 复原 IP 地址
1 | for(int a=1;a<4;a++) |
1143. 最长公共子序列
1 | if(text1.charAt(i-1)==text2.charAt(j-1)) |
560.和为K的子数组
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
1 | 输入:nums = [1,1,1], k = 2 |
1 | sum += nums[i]; |
209. 长度最小的子数组
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
1 | sum += nums[j]; |
974. 和可被 K 整除的子数组
给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。
示例:
输入:A = [4,5,0,-2,-3,1], K = 5
输出:7
解释:
有 7 个子数组满足其元素之和可被 K = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
为了可以处理数组一开始就能被k整除,需要设置 modK[0]=1;
1 | class Solution { |
287. 寻找重复数
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
快慢指针
1 | while(true) |
210. 课程表 II
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
示例 1:
输入: 2, [[1,0]]
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
先构造一个图
1 | List<Integer>[] lists = new ArrayList[numCourses]; |
//记录某个节点的入度
1 | int[] points = new int[numCourses]; |
初始化
1 | points[p[0]]++; |
所以入度为0加入到队列
1 | for(int i = 0; i < numCourses; i++){ |
依次对指向的结点度减一
1 | List<Integer> list = lists[p]; |
528. 按权重随机选择
给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。
例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。
也就是说,选取下标 i 的概率为 w[i] / sum(w) 。
先构造前缀,再二分
1 | //产生随机数 |
82. 删除排序链表中的重复元素 II
示例 1:
1 | 输入: 1->2->3->3->4->4->5 |
1 | while(head!=null && head.next!=null) |
8. 字符串转换整数 (atoi)
1 | if(s.length()==0 || s==null) return 0; |
50. Pow(x, n)
1 | if(n==0) return 1; |
147. 对链表进行插入排序
1 | while(head!=null && head.next!=null) |
264. 丑数 II
编写一个程序,找出第 n 个丑数。
丑数就是质因数只包含 2, 3, 5 的正整数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
三指针+三因子
1 | for(int i=1;i<n;i++) |
402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :
输入: num = “1432219”, k = 3
输出: “1219”
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
从左到右,找第一个比后面大的字符,删除,清零,k次扫描。
1 | for (int i = 0; i < k; i++) { |
86. 分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
1 | ListNode newTemp=partition(head.next,x); |
71. 简化路径
1 | if (item.isEmpty() || item.equals(".")) continue; |
22. 括号生成
回溯
1 | private void backtrack(List<String> res,int left,int right,String ans,int n) |
279. 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
1 | if(i>=j*j) |
139. 单词拆分
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict*,判定 *s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
1 | 输入: s = "leetcode", wordDict = ["leet", "code"] |
双指针+memo数组记录前n个是否匹配上
1 | for(int i=1;i<=n;i++) // 注意这一句是为了避免a ["a"]的情况 |
647. 回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
1 | 输入:"abc" |
动态规划,从数组尾部向前遍历,两个for
1 | if(s.charAt(i)==s.charAt(j)&& (j-i<=2 || dp[i+1][j-1]==true) ) |
75. 颜色分类
难度中等805
给定一个包含红色、白色和蓝色,一共 n
个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
三指针,current,left,right进行遍历
1 | if(nums[current]==0) |
394. 字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
示例 1:
1 | 输入:s = "3[a]2[bc]" |
用一个StringBuilder sb记录先前的字符串,两个栈一个数字栈,一个字符串栈
1 | for(char c : s.toCharArray()){ |
1438. 绝对差不超过限制的最长连续子数组
给你一个整数数组 nums
,和一个表示限制的整数 limit
,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit
。
1 | PriorityQueue<Integer> minQueue = new PriorityQueue<>(Comparator.naturalOrder()); |
807. 保持城市天际线
最后,从新数组的所有四个方向(即顶部,底部,左侧和右侧)观看的“天际线”必须与原始数组的天际线相同。 城市的天际线是从远处观看时,由所有建筑物形成的矩形的外部轮廓。 请看下面的例子。
两次两个for,取行和列最大值
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
两个for,数组长度为num1.length+num2.length,低位为 num[i+j+1]高位 num[i+j]
1 | for(int i = n1; i >= 0; --i) { |
496. 下一个更大元素 I
给你两个 没有重复元素 的数组 nums1
和 nums2
,其中nums1
是 nums2
的子集。
请你找出 nums1
中每个元素在 nums2
中的下一个比其大的值。
先用HashMap,遍历nums2.
503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
扩容数组,进行循环判断
1 | for (int i = 0; i < n*2; i++){ |
951. 翻转等价二叉树
我们可以为二叉树 T 定义一个翻转操作,如下所示:选择任意节点,然后交换它的左子树和右子树。
1 | if (root1 == null || root2 == null || root1.val != root2.val) { |
701. 二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
用一个parent记录父结点
1 | if(root == null){ |
1 | /** |
152. 乘积最大子数组
给你一个整数数组 nums
,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
1 | 输入: [2,3,-2,4] |
小于0就进行交换
1 | if(nums[i] < 0){ // 3 2 -1 -1 |
525. 连续数组
给定一个二进制数组, 找到含有相同数量的 0 和 1 的最长连续子数组(的长度)。
把0变为-1,前缀和+Map进行存储
1 | class Solution { |
468. 验证IP地址
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。
- 如果是有效的 IPv4 地址,返回
"IPv4"
; - 如果是有效的 IPv6 地址,返回
"IPv6"
; - 如果不是上述类型的 IP 地址,返回
"Neither"
。
对.进行split,要用IP.split(“\.”); split完后判断String[]的长度,是否为4或8
IPV4: 对每个数字字符串,判断是否为数字,然后累加,判断是否大于255
IPV6 : if (!((c >= ‘a’ && c <= ‘f’) || (c >= ‘A’ && c <= ‘F’) || (c >= ‘0’ && c <= ‘9’)))
1 | for (String string : strings) { |
260. 只出现一次的数字 III
给定一个整数数组 nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
全部异或取结果为K,开一个res数组,res[2] if(num&k)==0 res[1]^=num
1 | nt k=s & (-s); |
347. 前 K 个高频元素
示例 1:
1 | 输入: nums = [1,1,1,2,2,3], k = 2 |
1 | for(Integer key:map.keySet()) |
842. 将数组拆分成斐波那契序列
给定一个数字字符串 S
,比如 S = "123456579"
,我们可以将它分成斐波那契式的序列 [123, 456, 579]
。
采用dfs,首先考虑一个idx和一个存储先前字符串的idx
1 | public boolean dfs(String s,int idx,LinkedList<Integer> res) |
179. 最大数
给定一组非负整数 nums,重新排列它们每个数字的顺序(每个数字不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
示例 1:
输入:nums = [10,2]
输出:”210”
1 | Comparator<String> cmp=new Comparator<String>() |
198. 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
动态规划
1 | dp[0]=nums[0]; |
213. 打家劫舍 II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
1 | if (len <= 2) return len == 0 ? 0 : len == 1 ? nums[0] : Math.max(nums[0], nums[1]); |
609. 在系统中查找重复文件
给定一个目录信息列表,包括目录路径,以及该目录中的所有包含内容的文件,您需要找到文件系统中的所有重复文件组的路径。一组重复的文件至少包括二个具有完全相同内容的文件。
516. 最长回文子序列
给定一个字符串 s
,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s
的最大长度为 1000
。
1 | if(s.charAt(i) == s.charAt(j)){ |
416. 分割等和子集
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
- 每个数组中的元素不会超过 100
- 数组的大小不会超过 200
示例 1:
1 | 输入: [1, 5, 11, 5] |
1 | if(j-nums[i-1]<0) dp[i][j]=dp[i-1][j]; |
1 | boolean[] dp=new boolean[target+1]; |
17. 电话号码的字母组合
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
1 | 输入:digits = "23" |
设置一个idx往后遍历,对每一个idx取出Map的数据
1 | String value = map.get(digits.charAt(index)); |
49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
1 | 输入: ["eat", "tea", "tan", "ate", "nat", "bat"] |
1 | Map<String, List<String>> map = new HashMap<String, List<String>>(); |
334. 递增的三元子序列
给你一个整数数组 nums
,判断这个数组中是否存在长度为 3
的递增子序列。
如果存在这样的三元组下标 (i, j, k)
且满足 i < j < k
,使得 nums[i] < nums[j] < nums[k]
,返回 true
;否则,返回 false
。
1 | if (nums[i] <= first) { |
208. 实现 Trie (前缀树)
实现一个 Trie (前缀树),包含 insert
, search
, 和 startsWith
这三个操作。
示例:
1 | Trie trie = new Trie(); |
说明:
- 你可以假设所有的输入都是由小写字母
a-z
构成的。 - 保证所有输入均为非空字符串。
1 | private class TrieNode{ |
498. 对角线遍历
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。
定义r和c,初始为0
1 | if ((r + c) % 2 == 0) { |
238. 除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums
,其中 n > 1,返回输出数组 output
,其中 output[i]
等于 nums
中除 nums[i]
之外其余各元素的乘积。
示例:
1 | 输入: [1,2,3,4] |
双指针,两次遍历
1 | for(int i=nums.length-1;i>=0;i--) |
55. 跳跃游戏
给定一个非负整数数组 nums
,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
1 | 输入:nums = [2,3,1,1,4] |
1 | for(int i=0;i<nums.length;i++) |
45. 跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
1 | 输入: [2,3,1,1,4] |
80. 删除排序数组中的重复项 II
难度中等373
给定一个增序排列数组 nums
,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
len
表示的是删除重复元素后新序列的长度,同时也表示新元素进入新序列的索引;i
就是循环变量,用于遍历整个旧序列;if (len < 2) nums[len++] = nums[i];
的意思就是如果新序列的长度小于2(即新序列中不会存在两个相同的元素,这时候i
位置所在元素不会和新序列中的元素相同),直接将新元素加入到新序列中,并更新新序列的长度;if (nums[i] != nums[len-2]) nums[len++] = nums[i];
的意思就是如果新元素加入后不会和前两个元素构成3个相同的元素(nums[len-2]
就是直接取新序列中倒数第二个元素,如果该元素和新元素相同,说明加入后会构成3个相同的元素,显然是不符合题意的),就将新元素加入到新序列中,并更新新序列的长度;- 题意只要求将新序列紧挨在一起就行,多出的长度将不参与评测;
1 | class Solution { |
26. 删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
1 | for (int j = 1; j < nums.length; j++) { |
767. 重构字符串
给定一个字符串S
,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
1 | 输入: S = "aab" |
构造优先队列PriorityQueue
1 | if(cnt[i]!=0) |
523. 连续的子数组和
给定一个包含 非负数 的数组和一个目标 整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 nk,其中 n 也是一个*整数**。
示例 1:
1 | 输入:[23,2,4,6,7], k = 6 |
map.put(0,-1)是为了避免数组前几位mod为0
1 | if(nums.length < 2) return false; |
96. 不同的二叉搜索树
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:
1 | 输入: 3 |
1 | //dp[n]=dp[0]*dp[n-1-0]+dp[1]*dp[n-1-1] |
376. 摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5]
是一个摆动序列,因为差值 (6,-3,5,-7,3)
是正负交替出现的。相反, [1,4,7,2,5]
和 [1,7,4,5,5]
不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
示例 1:
1 | 输入: [1,7,4,9,2,5] |
1 | class Solution { |
1498. 满足条件的子序列数目
给你一个整数数组 nums
和一个整数 target
。
请你统计并返回 nums
中能满足其最小元素与最大元素的 和 小于或等于 target
的 非空 子序列的数目。
由于答案可能很大,请将结果对 10^9 + 7 取余后返回。
排序+双指针
1 | for(int i=1;i<n;i++){ |
863. 二叉树中所有距离为 K 的结点
给定一个二叉树(具有根结点 root
), 一个目标结点 target
,和一个整数值 K
。
返回到目标结点 target
距离为 K
的所有结点的值的列表。 答案可以以任何顺序返回。
示例 1:
1 | 输入:root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2 |
1 | public List<Integer> distanceK(TreeNode root, TreeNode target, int K) { |
45. 跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
1 | 输入: [2,3,1,1,4] |
我来大概解释一下吧,献丑了,鉴于题目已经给了前提,那就是肯定能到达最后一个元素,那么只要考虑每一跳所能达到的最远位置就行了,也就是每次都选择最远可达的点,reach是当前需要进行跳跃的右界限,nextReach是下一次跳跃的右界限,nextReach的值一直动态更新,以保证每次跳跃都是最远的
1 | class Solution { |
977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
1 | 输入:nums = [-4,-1,0,3,10] |
1 | while(l<=r) |
680. 验证回文字符串 Ⅱ
给定一个非空字符串 s
,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
1 | 输入: "aba" |
1 | while(i<j) |
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
1 | 输入:strs = ["flower","flow","flight"] |
1 | for(int i=0;i<strs[0].length();i++) |
283. 移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
1 | 输入: [0,1,0,3,12] |
1 | for(int i=0;i<nums.length;i++) |
242. 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
开一个new int[26]的数组 ,接下来一个+,一个-
1 | for(int i = 0; i< s.length(); i++) { |
572. 另一个树的子树
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
1 | public boolean isSame(TreeNode s,TreeNode t) |
190. 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
1 | for(int i=0;i<32;i++) |
459. 重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
1 | 输入: "abab" |
1 | return (s+s).substring(1,s.length()*2-1).indexOf(s)!=-1; |
7. 整数反转
给你一个 32 位的有符号整数 x
,返回 x
中每位上的数字反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1]
,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
1 | while(x!=0) |
204. 计数质数
统计所有小于非负整数 n
的质数的数量。
示例 1:
1 | 输入:n = 10 |
1 | for(int i=2;i<n;i++) |
202. 快乐数
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果 可以变为 1,那么这个数就是快乐数。
如果 n
是快乐数就返回 true
;不是,则返回 false
。
示例 1:
1 | 输入:19 |
1 | public boolean isHappy(int n) { |
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
1 | public void helper(TreeNode root,int count) |
922. 按奇偶排序数组 II
给定一个非负整数数组 A
, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i]
为奇数时,i
也是奇数;当 A[i]
为偶数时, i
也是偶数。
你可以返回任何满足上述条件的数组作为答案。
1 | class Solution { |
9. 回文数
1 | while(x>0) |
1299. 将每个元素替换为右侧最大元素
给你一个数组 arr
,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1
替换。
完成所有替换操作后,请你返回这个数组。
1 | for (int i = arr.length - 1; i >= 0; i--) { |
122. 买卖股票的最佳时机 II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
1 | dp[0][0]=0; // 不持有 |
405. 数字转换为十六进制数
给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。
注意:
- 十六进制中所有字母(
a-f
)都必须是小写。 - 十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符
'0'
来表示;对于其他情况,十六进制字符串中的第一个字符将不会是0字符。 - 给定的数确保在32位有符号整数范围内。
- 不能使用任何由库提供的将数字直接转换或格式化为十六进制的方法。
示例 1:
1 | 输入: |
1 | char[] hex="0123456789abcdef".toCharArray(); |
836. 矩形重叠
矩形以列表 [x1, y1, x2, y2]
的形式表示,其中 (x1, y1)
为左下角的坐标,(x2, y2)
是右上角的坐标。矩形的上下边平行于 x 轴,左右边平行于 y 轴。
如果相交的面积为 正 ,则称两矩形重叠。需要明确的是,只在角或边接触的两个矩形不构成重叠。
给出两个矩形 rec1
和 rec2
。如果它们重叠,返回 true
;否则,返回 false
。
示例 1:
1 | 输入:rec1 = [0,0,2,2], rec2 = [1,1,3,3] |
1 | if(rec2[1] >= rec1[3] || rec1[1] >= rec2[3]){ |
165. 比较版本号
给你两个版本号 version1
和 version2
,请你比较它们。
版本号由一个或多个修订号组成,各修订号由一个 '.'
连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33
和 0.1
都是有效的版本号。
比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1
和修订号 001
相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0
。例如,版本 1.0
小于版本 1.1
,因为它们下标为 0
的修订号相同,而下标为 1
的修订号分别为 0
和 1
,0 < 1
。
返回规则如下:
- 如果
*version1* > *version2*
返回1
, - 如果
*version1* < *version2*
返回-1
, - 除此之外返回
0
。
1 | while(i<version1.length() || j<version2.length()) |
443. 压缩字符串
给定一组字符,使用原地算法将其压缩。
压缩后的长度必须始终小于或等于原数组长度。
数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。
在完成原地修改输入数组后,返回数组的新长度。
1 | while(idx<n) |
316. 去除重复字母
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
1 | 输入:s = "bcabc" |
思路就是 遇到一个新字符 如果比栈顶小 并且在新字符后面还有和栈顶一样的 就把栈顶的字符抛弃了
1013. 将数组分成和相等的三个部分
给你一个整数数组 A
,只有可以将其划分为三个和相等的非空部分时才返回 true
,否则返回 false
。
形式上,如果可以找出索引 i+1 < j
且满足 A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1]
就可以将数组三等分。
示例 1:
1 | 输入:[0,2,1,-6,6,-7,9,1,2,0,1] |
1 | // 值得注意的是最后一句return cnt >= 3, 为什么是大于等于呢? 显然, 如果找到等于 sum / 3的部分和数量cnt < 3, 那么一定不满足题意, cnt = 3也很好理解, 问题就在于, 当找出两个等于 sum / 3的部分和后, 数组剩余的部分其和一定也是 sum / 3, 但是考虑到sum = 0的特殊情况, 最后的sum / 3的数组中, 仍然可能含有部分和为0的子结构, 导致计数变量cnt > 3 |
628. 三个数的最大乘积
给你一个整型数组 nums
,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
1 | Arrays.sort(nums); |
227. 基本计算器 II
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
示例 1:
1 | 输入:s = "3+2*2" |
示例 2:
1 | 输入:s = " 3/2 " |
1 | class Solution { |
224. 基本计算器
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
示例 1:
1 | 输入:s = "1 + 1" |
示例 2:
1 | 输入:s = " 2-1 + 2 " |
1 | //https://leetcode-cn.com/problems/basic-calculator/solution/ji-ben-ji-suan-qi-zhan-dui-yu-gua-hao-yo-a1f0/ |
N进制相加
1 | import java.util.*; |
剑指offer
剑指 Offer 05. 替换空格
难度简单80收藏分享切换为英文接收动态反馈
请实现一个函数,把字符串 s
中的每个空格替换成”%20”。
示例 1:
1 | 输入:s = "We are happy." |
1 | while (P1 >= 0 && P2 > P1) { |
12. 矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,”b“,”c”,”e”],
[“s”,”f“,”c“,”s”],
[“a”,”d”,”e“,”e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
1 | 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" |
1 | vis[i][j]=1; |
13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0]
到坐标 [m-1,n-1]
。一个机器人从坐标 [0, 0]
的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
1 | 输入:m = 2, n = 3, k = 1 |
1 | public int dfs(int m,int n,int k,int x,int y) |
15. 二进制中1的个数
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
1 | 输入:00000000000000000000000000001011 |
1 | while(n!=0) |
21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
1 | 输入:nums = [1,2,3,4] |
1 | for(int i=0;i<nums.length;i++) |
24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
1 | while(head!=null) |
26. 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
1 | public boolean dfs(TreeNode t1,TreeNode t2) |
28. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
1 | TreeNode t1=q.poll(); |
31.栈的压入、弹出序列
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
1 | for(int i=0;i<pushed.length;i++) |
30. 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
1 | MinStack minStack = new MinStack(); |
1 | public void push(int x) { |
03. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
1 | 输入: |
1 | for(int i=0;i<nums.length;i++) |
剪绳子
给你一根长度为 n
的绳子,请把绳子剪成整数长度的 m
段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1]
。请问 k[0]*k[1]*...*k[m-1]
可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
1 | 输入: 2 |
1 | int[] dp=new int[n+1]; |
1 | while(n>=5) |
33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
1 | 5 |
1 | int rootValue=num[right]; |
46. 把数字翻译成字符串
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
1 | 输入: 12258 |
1 | 输入: 12258 |
1 | if(str.charAt(i-2) != '0' && |
37. 序列化二叉树
1 | public String serialize(TreeNode root) { |
41. 数据流中的中位数
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构
用大顶堆+小顶堆方法,可以看作大顶堆是普通班,小顶堆是实验班。数量上时刻保持 小顶-大顶<=1(两堆相等或者小顶比大顶多一个)。
新学生先入普通班(大顶堆),此时可能会失去平衡了,于是取大顶堆的第一个(班里最好的学生)加入实验班(小顶堆),判断若数量过多(不是等于或多一个),取第一个(实验班里最差的学生)到普通班(大顶堆)里。 取中位数的时候,若两堆数量相等,则各取堆顶取平均,若小顶比大顶多一,则多的那一个就是中位数。
1 | class MedianFinder { |
51. 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
1 | 输入: [7,5,6,4] |
1 | public void merge(int[] nums,int l,int r) |
53 - II. 0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
1 | if(nums[mid]>mid) |
68 - I. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
1 | if (root.val > p.val && root.val > q.val) |
61. 扑克牌中的顺子
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
1 | 输入: [1,2,3,4,5] |
1 | Set<Integer> repeat = new HashSet<>(); |
88. 合并两个有序数组
给你两个有序整数数组 nums1
和 nums2
,请你将 nums2
合并到 nums1
中,使 nums1
成为一个有序数组。
初始化 nums1
和 nums2
的元素数量分别为 m
和 n
。你可以假设 nums1
的空间大小等于 m + n
,这样它就有足够的空间保存来自 nums2
的元素。
1 | class Solution { |
69. x 的平方根
实现 int sqrt(int x)
函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
1 | int mid=left+(right-left+1)/2; |
56 - II. 数组中数字出现的次数 II
在一个数组 nums
中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
1 | for(int i=0;i<32;i++) |
53 - II. 0~n-1中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
1 | while(left<right) |
57 - II. 和为s的连续正数序列
输入一个正整数 target
,输出所有和为 target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
1 | 输入:target = 9 |
59 - II. 队列的最大值
请定义一个队列并实现函数 max_value
得到队列里的最大值,要求函数max_value
、push_back
和 pop_front
的均摊时间复杂度都是O(1)。
若队列为空,pop_front
和 max_value
需要返回 -1
1 | public void push_back(int value) { |
65. 不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
1 | class Solution { |
64. 求1+2+…+n
求 1+2+...+n
,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
1 | public int sumNums(int n) { |
59 - I. 滑动窗口的最大值
1 | for(int i=0;i<num.length;i++) |
62. 圆圈中最后剩下的数字
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
1 | int ans=0; |
57 - II. 和为s的连续正数序列
1 | while(i<=target/2) |
17. 打印从1到最大的n位数
输入数字 n
,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
1 | private void print1ToMaxOfNDigits(char[] number, int digit) { |
进制转换
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数
1 | public String solve (int M, int N) { |
Hot100
1. 两数之和
1 | int ret=target-nums[i]; |
20. 有效的括号
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
1 | if(stack.isEmpty()) |
34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
1 | while(l<r) |
136. 只出现一次的数字38
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
1 | for(int i=1;i<nums.length;i++) |
226. 翻转二叉树
1 | TreeNode left=invertTree(root.left); |
1 | while (!queue.isEmpty()){ |
494. 目标和
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 +
和 -
。对于数组中的任意一个整数,你都可以从 +
或 -
中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例:
1 | 输入:nums: [1, 1, 1, 1, 1], S: 3 |
1 | // 目标和不可能大于总和 |
543. 二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1 | 1 |
1 | private int depth(TreeNode root) |
322. 零钱兑换
给定不同面额的硬币 coins
和一个总金额 amount
。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
示例 1:
1 | 输入:coins = [1, 2, 5], amount = 11 |
1 | for(int i=1;i<=coins.length;i++) |
518. 零钱兑换 II
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
1 | for(int i = 1; i < dp.length; i++) |
860. 柠檬水找零
1 | 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 |
1 | int five = 0,ten = 0; |
338. 比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
1 | 输入: 2 |
示例 2:
1 | 输入: 5 |
- 方法一:i & (i - 1)可以去掉i最右边的一个1(如果有),因此 i & (i - 1)是比 i 小的,而且i & (i - 1)的1的个数已经在前面算过了,所以i的1的个数就是 i & (i - 1)的1的个数加上1
1 | public int[] countBits(int num) { |
617. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
1 | while (!queue.isEmpty()) { |
1 | class Solution { |
448. 找到所有数组中消失的数字
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
1 | 输入: |
438. 找到字符串中所有字母异位词
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
- 字母异位词指字母相同,但排列不同的字符串。
- 不考虑答案输出的顺序。
示例 1:
1 | public List<Integer> findAnagrams(String s, String p) { |
538. 把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node
的新值等于原树中大于或等于 node.val
的值之和。
提醒一下,二叉搜索树满足下列约束条件:
- 节点的左子树仅包含键 小于 节点键的节点。
- 节点的右子树仅包含键 大于 节点键的节点。
- 左右子树也必须是二叉搜索树。
1 | class Solution { |
131. 分割回文串
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = “aab”
输出:[[“a”,”a”,”b”],[“aa”,”b”]]
示例 2:
输入:s = “a”
输出:[[“a”]]
1 | class Solution { |
12. 整数转罗马数字
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
1 | 字符 数值 |
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
1 | public String intToRoman(int num) { |
自创题
CodeTop easy
258. 各位相加
给定一个非负整数 num
,反复将各个位上的数字相加,直到结果为一位数。
示例:
1 | 输入: 38 |
1 | class Solution { |
728. 自除数
自除数 是指可以被它包含的每一位数除尽的数。
例如,128 是一个自除数,因为 128 % 1 == 0
,128 % 2 == 0
,128 % 8 == 0
。
还有,自除数不允许包含 0 。
给定上边界和下边界数字,输出一个列表,列表的元素是边界(含边界)内所有的自除数。
示例 1:
1 | 输入: |
1 | public List<Integer> selfDividingNumbers(int left, int right) { |
706. 设计哈希映射
1 | class Node{ |
Hard
4. 寻找两个正序数组的中位数
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
示例 1:
1 | 输入:nums1 = [1,3], nums2 = [2] |
1 | int left=(n+m+1)/2; |
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
双指针双max,一个left,一个right,一个left_max,一个right_max
1 | while (left < right) { |
72. 编辑距离
给你两个单词 word1
和 word2
,请你计算出将 word1
转换成 word2
所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
1 | for(int i=0;i<n1;i++) |
76. 最小覆盖子串5
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:如果 s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
1 | 输入:s = "ADOBECODEBANC", t = "ABC" |
先开need窗口记录t,当满足
1 | if (needs[ch] > 0 && needs[ch] >= window[ch]) { |
说明此时还是需要的,接下来移动到不满足为主,
1 | //移动到不满足条件为止 |
128. 最长连续序列
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
示例 1:
1 | 输入:nums = [100,4,200,1,3,2] |
1 | if(!set.contains(num-1)) |
124. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root
,返回其 最大路径和 。
1 | int leftMax = Math.max(0, dfs(root.left)); |
239. 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 1:
1 | 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 |
1 | for(int i = 0;i < nums.length;i++){ |
32. 最长有效括号
给你一个只包含 '('
和 ')'
的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
1 | 输入:s = "(()" |
1 | for (int i = 1; i < s.length(); i++) { |
862. 和至少为 K 的最短子数组
1 | for (int i = 0; i < A.length; i++) { |
329. 矩阵中的最长递增路径
给定一个 m x n
整数矩阵 matrix
,找出其中 最长递增路径 的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。
示例 1:
1 | public int longestIncreasingPath(int[][] matrix) { |
44. 通配符匹配
给定一个字符串 (s
) 和一个字符模式 (p
) ,实现一个支持 '?'
和 '*'
的通配符匹配。
1 | '?' 可以匹配任何单个字符。 |
两个字符串完全匹配才算匹配成功。
说明:
s
可能为空,且只包含从a-z
的小写字母。p
可能为空,且只包含从a-z
的小写字母,以及字符?
和*
。
示例 1:
1 | 输入: |
1 | dp[0][0] = true; |
99. 恢复二叉搜索树
给你二叉搜索树的根节点 root
,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
示例 1:
1 | 输入:root = [1,3,null,null,2] |
1 | public void recoverTree(TreeNode root) { |
10. 正则表达式匹配
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
'.'
匹配任意单个字符'*'
匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s
的,而不是部分字符串。
示例 1:
1 | 输入:s = "aa" p = "a" |
1 | for(int i=0;i<n2;i++) |
440. 字典序的第K小数字
难度困难194
给定整数 n
和 k
,找到 1
到 n
中字典序第 k
小的数字。
注意:1 ≤ k ≤ n ≤ 109。
示例 :
1 | 输入: |
1 | public int findKthNumber(int n, int k) { |
124. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
1 | public int dfs(TreeNode root) { |
99. 恢复二叉搜索树
给你二叉搜索树的根节点 root
,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?