题目 通过率 难度
1. 两数之和 51.8% 简单
2. 两数相加 40.7% 中等
3. 无重复字符的最长子串 37.8% 中等
hashMap储存位置+滑动窗口left = Math.max(left,map.get(s.charAt(right))+1)
4. 寻找两个正序数组的中位数 40.6% 困难
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
int len = m + n;
if (len % 2 == 1)
//总长度为奇数如9 ,则求第5小的数
return getKth(nums1, 0, n - 1, nums2, 0, m - 1, len / 2 + 1);
else
return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, (len) / 2) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, (len) / 2 + 1)) / 2.0; //注意是2.0
}
private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
if (len1 < len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);//保证长度长的始终在前
// 递归结束条件1,两个数组长度不等时。较短的数组长度为0 总长度为k。
if (len2 == 0) return nums1[start1 + k - 1];
// 递归结束条件2,两个数组长度相等时,就是第1小,返回小的。
if (k == 1) return Math.min(nums1[start1], nums2[start2]);
int addLen1 = Math.min(len1, k / 2); //当某一个数组淘汰元素以后不足k/2 取全部
int addLen2 = Math.min(len2, k / 2);
if (nums1[start1 + addLen1 - 1] > nums2[start2 + addLen2 - 1]) { //把小的一半扔掉
return getKth(nums1, start1, end1, nums2, start2 + addLen2, end2, k - addLen2);
} else {
return getKth(nums1, start1 + addLen1, end1, nums2, start2, end2, k - addLen1);
}
}
}
5. 最长回文子串 35.1% 中等
定义 dp【i】【j】表示字符串从i到j的位置的最长回文子串的长度
状态:dp[i][j] 表示字符串s在[i,j]区间的子串是否是一个回文串。
状态转移方程:当 s[i] == s[j](j - i < 2 ) dp[i][j] = j-i+1;
dp[i + 1][j - 1]>0 表示i+1到j-1之间为回文子串 时,dp[i][j]= 中间长度 +2; 不等的时候就为0
int[][] dp = new int[s.length() ][s.length() ]; int maxL = 0,start = 0; for (int i = s.length()-1; i >= 0; i--) { for (int j = i; j < s.length(); j++) { if (s.charAt(i) == s.charAt(j)) { if (j - i < 3) { dp[i][j] = j-i+1; //注意 } else if (i < s.length() && j > 0 && dp[i + 1][j - 1] > 0) { dp[i][j] = dp[i + 1][j - 1] + 2; } if(dp[i][j]>maxL){ maxL=dp[i][j];start = i; } } } }
for (int r = 1; r < strLen; r++) { for (int l = 0; l < r; l++) { if (s.charAt(l) == s.charAt(r) && (r - l <= 2 || dp[l + 1][r - 1])) { dp[l][r] = true; if (r - l + 1 > maxLen) { maxLen = r - l + 1; maxStart = l; maxEnd = r; } } }
10. 正则表达式匹配 31.6% 困难
11. 盛最多水的容器 63.3% 中等
双指针,计算面积、短板对应的指针移动,比较最大面积
15. 三数之和 33.1% 中等
排序+双指针
17. 电话号码的字母组合 57.1% 中等
回溯
19. 删除链表的倒数第 N 个结点 42.7% 中等
快慢指针
20. 有效的括号 44.4% 简单 栈模拟
21. 合并两个有序链表 66.6% 简单 、、
22. 括号生成 77.3% 中等 模拟回溯
23. 合并K个升序链表 55.8% 困难
小根堆 Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
31. 下一个排列 37.3% 中等
在尽可能靠右的低位进行交换,需要从后向前查找
将一个 尽可能小的「大数」 与前面的「小数」交换。
逆置
[j,end)
,使其升序
32. 最长有效括号 35.5% 困难
dp[i] 数组,其中第 ii 个元素表示以下标为 ii 的字符结尾的最长有效子字符串的长度。
if s[i] == '(' :
dp[i] = 0
if s[i] == ')' :
if s[i - 1] == '(' :
dp[i] = dp[i - 2] + 2 #要保证i - 2 >= 0if s[i - 1] == ')' and s[i - dp[i - 1] - 1] == '(' :
if i - dp[i - 1] - 2 >= 0
dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 #要保证i - dp[i - 1] - 2 >= 0esle
dp[i] = dp[i - 1] + 2;
33. 搜索旋转排序数组 42.5% 中等
不重复搜索旋转数组,比较的时候区分一下哪边有序 哪边无序
if (nums[mid]==target)
return mid;
else if (nums[low]<=nums[mid]){
if (nums[low] <= target && target <=nums[mid])
high = mid-1;
else
low = mid+1;
}else{
if (nums[mid] <= target && target <=nums[high])
low = mid+1;
else
high = mid -1;
}
34. 在排序数组中查找元素的第一个和最后一个位置 42.5% 中等
39. 组合总和 72.7% 中等
典型回溯
class Solution { private List<List<Integer>> res = new ArrayList<>(); public List<List<Integer>> combinationSum(int[] candidates, int target) { List<Integer> path = new ArrayList<>(); Arrays.sort(candidates); backtrack(path,candidates,target,0,0); return res; } private void backtrack(List<Integer> path,int[] candidates,int target,int sum,int begin) { if(sum == target) { res.add(new ArrayList<>(path)); return; } for(int i = begin;i < candidates.length;i++) { int rs = candidates[i] + sum; if(rs <= target) { path.add(candidates[i]); backtrack(path,candidates,target,rs,i); path.remove(path.size()-1); } else { break; } } } }
42. 接雨水 57.2% 困难
求最值,最大值左边每个轴对应的面积是 leftmax - height[i],右边同理
class Solution {
public int trap(int[] height) {
int m = -1;
int mi = 0;
int ans = 0;
for (int i = 0; i < height.length; i++) {
if (height[i] > m) {
m = height[i];
mi = i;
}
}
int leftmax = 0;
for (int i = 0; i < mi; i++) {
if (height[i] > leftmax)
leftmax = height[i];
ans += leftmax > height[i] ? (leftmax - height[i]) : 0;
}
int rightmax = 0;
for (int i = height.length - 1; i > mi; i--) {
if (height[i] > rightmax)
rightmax = height[i];
ans += rightmax > height[i] ? (rightmax - height[i]) : 0;
}
return ans;
}
}
46. 全排列 78.2% 中等
import java.util.ArrayList; import java.util.List; class Solution { private List<List<Integer>> res=new ArrayList<>(); private ArrayList<Integer> tmp = new ArrayList<>(); private boolean[] used; public List<List<Integer>> permute(int[] nums) { used= new boolean[nums.length]; dfs(0,nums); return res; } public void dfs(int deep,int[] nums){ if(deep==nums.length){ res.add(new ArrayList<>(tmp)); return; } for (int i = 0; i <nums.length ; i++) { if(!used[i]) { used[i]= true; tmp.add(nums[i]); dfs(deep + 1, nums); tmp.remove(tmp.size() - 1); used[i]=false; } } } }
48. 旋转图像 73.4% 中等
49. 字母异位词分组 66.3% 中等
hashMap计数 (将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键)a3b2c4
Map<String, List<String>> map = new HashMap<String, List<String>>();
53. 最大子序和 55.0% 简单
给定一个整数数组
nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。dp[i]= max(dp[i-1]+nums[i] , nums[i])
55. 跳跃游戏 43.1% 中等
int k = 0;
for (int i = 0; i < nums.length; i++) {
if (i > k) return false;
k = Math.max(k, i + nums[i]);
}
return true;
56. 合并区间 46.5% 中等
我们用数组 merged 存储最终的答案。
首先,我们将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 merged 数组中,并按顺序依次考虑之后的每个区间:
如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 merged 的末尾;
否则,它们重合,我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点,将其置为二者的较大值。
class Solution { public int[][] merge(int[][] intervals) { Arrays.sort(intervals,(v1,v2)->(v1[0]-v2[0]) ); List<int[]> merged = new ArrayList<int[]>(); for (int i = 0; i < intervals.length; ++i) { int L = intervals[i][0], R = intervals[i][1]; if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) { merged.add(new int[]{L, R}); } else { merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R); } } return merged.toArray(new int[merged.size()][]); } }
62. 不同路径 65.9% 中等
注意这样做,会发生出浮点数错误 public int uniquePaths(int m, int n) { double ans=1; n = n+m-2; m = m-1; for(int i=1;i<=m;i++){ ans *= (double)(n-m+i)/i; System.out.println( (double) (n+m+i)/i +ans); } return (int) ans; n=9 m=8时由于计算机的精度表示问题 会出现错误 正确做法: ans = ans*(n-m+i)/i; 这次能保证每次除的都是整数
或者
dp
64. 最小路径和 68.8% 中等
给定一个包含非负整数的 m x n
网格 grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]
70. 爬楼梯 52.7% 简单
72. 编辑距离 61.2% 困难
给你两个单词 word1
和 word2
,请你计算出将 word1
转换成 word2
所使用的最少操作数 。
public int minDistance(String word1, String word2) { int[][] dp = new int[word1.length()+1][word2.length()+1]; for (int i = 0; i <=word1.length() ; i++) { for (int j = 0; j <=word2.length() ; j++) { if(i==0||j==0){ dp[i][j] = (i!=0?i:j); //增加或者替换 continue; } if(word1.charAt(i-1)==word2.charAt(j-1)) // 相等的情况下 dp[i][j] = dp[i-1][j-1] ; else dp[i][j] = Math.min(dp[i-1][j-1], //替换、增加、删除 Math.min(dp[i-1][j],dp[i][j-1]))+1; } } return dp[word1.length()][word2.length()]; }
75. 颜色分类 59.3% 中等
定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
三个指针,i指向0的,j依次遍历,k指向下一个2的位置,依次遍历即可(注意2交换完以后仍有可能是2)
76. 最小覆盖子串 42.3% 困难
给你一个字符串
s
、一个字符串t
。返回s
中涵盖t
所有字符的最小子串。如果s
中不存在涵盖t
所有字符的子串,则返回空字符串""
。两个HashMap+滑动窗口解决
78. 子集 80.0% 中等
给你一个整数数组
nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]两种解法:1、递归回溯,注意递归的时候
2. 二进制对应
public void dfs(int cur, int[] nums) { if(cur>nums.length) return; ans.add(new ArrayList<Integer>(t)); for(int i=cur;i<nums.length;i++){ t.add(nums[i]); //区别所在 一般这个地方是dfs(cur+1) dfs(i + 1, nums); t.remove(t.size() - 1); } } }
public List<List<Integer>> subsets(int[] nums) { int n = 1 << (nums.length); //全1的时候 for (int i = 0; i < n; i++) { // 0(000) 1(001) ...n(111) t.clear(); for (int j = 0; j < nums.length; j++) { //按位与 if ((i & (1 << j))!=0) //注意这个地方只能写不等于0 不能写等于1 t.add(nums[j]); } ans.add(new ArrayList<>(t)); } return ans; }
79. 单词搜索 45.6% 中等
给定一个
m x n
二维字符网格board
和一个字符串单词word
。如果word
存在于网格中,返回true
;否则,返回false
。典型dfs回溯
class Solution { static boolean[][] vis; public boolean exist(char[][] board, String word) { vis = new boolean[board.length][board[0].length]; for (int i = 0; i < board.length; ++i) { for (int j = 0; j < board[i].length; ++j) { if (dfs(board, word, i, j, 0)) { return true; } } } return false; } public boolean dfs(char[][] board, String word, int i, int j, int k) { if (k == word.length()) { return true; } if (i < 0 || j < 0 || i >= board.length || j >= board[i].length || vis[i][j] || word.charAt(k) != board[i][j]) { return false; } vis[i][j] = true; boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i, j - 1, k + 1); vis[i][j] = false; return res; } }
84. 柱状图中最大的矩形 43.2% 困难
85. 最大矩形 51.6% 困难
94. 二叉树的中序遍历 75.6% 简单
96. 不同的二叉搜索树 69.9% 中等
98. 验证二叉搜索树 34.8% 中等
101. 对称二叉树 56.0% 简单
102. 二叉树的层序遍历 64.2% 中等
104. 二叉树的最大深度 76.5% 简单
105. 从前序与中序遍历序列构造二叉树 70.3% 中等
114. 二叉树展开为链表 72.5% 中等
121. 买卖股票的最佳时机 57.2% 简单
124. 二叉树中的最大路径和 44.2% 困难
注意,可以不经过 叶子结点、最上层的根节点。(另外注意ans最好不要设置成static)
public int help(TreeNode root){ // 当前节点开始左/右边的半路劲和 if(root==null) return 0; int l=Math.max(help(root.left),0); // 左子树取还是不取 int r=Math.max(help(root.right),0); ans=Math.max(ans,root.val+l+r); //仅仅计算结果,可忽略 return root.val+Math.max(l,r); // 以当前节点 左边的路劲 还是右边的路劲 }
128. 最长连续序列 54.3% 中等
136. 只出现一次的数字 71.9% 简单
139. 单词拆分 51.2% 中等
141. 环形链表 51.2% 简单
142. 环形链表 II 55.1% 中等
146. LRU 缓存机制 52.6% 中等
148. 排序链表 66.8% 中等
152. 乘积最大子数组 42.0% 中等
155. 最小栈 57.2% 简单
160. 相交链表 61.1% 简单
169. 多数元素 66.4% 简单
198. 打家劫舍 51.0% 中等
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
dp 方程 dp[i] = max(dp[i-2]+nums[i], dp[i-1])
200. 岛屿数量 55.0% 中等
深度优先遍历,遍历过的修改。
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1'){
dfs(grid, i, j);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
grid[i][j] = '0';
dfs(grid, i + 1, j);
dfs(grid, i, j + 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
}
206. 反转链表 72.2% 简单
207. 课程表 54.5% 中等
208. 实现 Trie (前缀树) 71.6% 中等
215. 数组中的第K个最大元素 64.7% 中等
221. 最大正方形 47.1% 中等
226. 翻转二叉树 78.7% 简单
234. 回文链表 49.1% 简单
236. 二叉树的最近公共祖先 67.9% 中等
238. 除自身以外数组的乘积 72.2% 中等
239. 滑动窗口最大值 49.6% 困难
240. 搜索二维矩阵 II 47.3% 中等
253. 会议室 II 49.5% 中等
279. 完全平方数 63.0% 中等
283. 移动零 63.9% 简单
287. 寻找重复数 66.3% 中等
297. 二叉树的序列化与反序列化 55.6% 困难
300. 最长递增子序列 51.0% 中等
301. 删除无效的括号 52.2% 困难
309. 最佳买卖股票时机含冷冻期 60.3% 中等
312. 戳气球 68.2% 困难
322. 零钱兑换 44.2% 中等
337. 打家劫舍 III 60.9% 中等
338. 比特位计数 78.7% 简单
347. 前 K 个高频元素 62.2% 中等
394. 字符串解码 55.1% 中等
399. 除法求值 59.2% 中等
406. 根据身高重建队列 73.5% 中等
416. 分割等和子集 50.6% 中等
437. 路径总和 III 56.7% 中等
438. 找到字符串中所有字母异位词 51.5% 中等
448. 找到所有数组中消失的数字 64.7% 简单
461. 汉明距离 81.1% 简单
494. 目标和 50.2% 中等
538. 把二叉搜索树转换为累加树 69.4% 中等
543. 二叉树的直径 54.7% 简单
560. 和为K的子数组 44.7% 中等
581. 最短无序连续子数组 40.3% 中等
617. 合并二叉树 78.8% 简单
621. 任务调度器 56.8% 中等
647. 回文子串 65.5% 中等
给你一个字符串
s
,请你统计并返回这个字符串中 回文子串 的数目。这道题主要的思路是中心扩展;