LeetCode 热题 HOT 100之JAVA解法

  • 第1题 两数之和(简单)
    • 代码
  • 第2题 两数相加(中等)
    • 代码
  • 第3题 无重复字符的最长子串(中等)
    • 代码
  • 第4题 寻找两个正序数组的中位数(困难)
    • 代码
  • 第5题 最长回文子串(中等)
    • 代码
  • 第10题 正则表达式匹配(困难)
    • 代码
  • 第11题 盛最多水的容器(中等)
    • 代码
  • 第15题 三数之和(中等)
    • 代码
  • 第17题 电话号码的字母组合(中等)
    • 代码
  • 第19题 删除链表的倒数第 N 个结点(中等)
    • 代码
  • 第20题 有效的括号(简单)
    • 代码
  • 第21题 合并两个有序链表(简单)
    • 代码
  • 第22题 括号生成(中等)
    • 代码
  • 第23题 合并K个升序链表(困难)
    • 代码
  • 第31题 下一个排列(中等)
    • 代码
  • 第32题 最长有效括号(困难)
    • 代码
  • 第33题 搜索旋转排序数组(中等)
    • 代码
  • 第34题 在排序数组中查找元素的第一个和最后一个位置(中等)
    • 代码
  • 第39题 组合总和(中等)
    • 代码
  • 第42题 接雨水(困难)
    • 代码
  • 第46题 全排列(中等)
    • 代码
  • 第49题 字母异位词分组(中等)
    • 代码
  • 第53题 最大子序和(简单)
    • 代码
  • 第55题 跳跃游戏(中等)
    • 代码
  • 第56题 合并区间(中等)
    • 代码
  • 第62题 不同路径(中等)
    • 代码
  • 第64题 最小路径和(中等)
    • 代码
  • 第70题 爬楼梯(简单)
    • 代码
  • 第72题 编辑距离(困难)
    • 代码
  • 第75题 颜色分类(中等)
    • 代码
  • 第76题 最小覆盖子串(困难)
    • 代码
  • 第78题 子集(中等)
    • 代码
  • 第79题 单词搜索(中等)
    • 代码
  • 第84题 柱状图中最大的矩形(困难)
    • 代码
  • 第85题 最大矩形(困难)
    • 代码
  • 第94题 二叉树的中序遍历(简单)
    • 代码
  • 第96题 不同的二叉搜索树(中等)
    • 代码
  • 第98题 验证二叉搜索树(中等)
    • 代码
  • 第101题 对称二叉树(简单)
    • 代码
  • 第102题 二叉树的层序遍历(中等)
    • 代码
  • 第104题 二叉树的最大深度(简单)
    • 代码

第1题 两数之和(简单)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

示例 1:

输入 输出
nums = [2,7,11,15], target = 9 [0,1]

解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入 输出
nums = [3,2,4], target = 6 [1,2]

示例 3:

输入 输出
nums = [3,3], target = 6 [0,1]

代码

// 两数之和:哈希表
class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer,Integer>hashtable = new HashMap<Integer,Integer>();//建立哈希表for(int i=0;i<nums.length;++i){//遍历数组if(hashtable.containsKey(target-nums[i])){//如果哈希表中存在目标值减去当前值return new int[]{hashtable.get(target-nums[i]),i};//则返回另一个数的索引以及当前数的索引}hashtable.put(nums[i],i);//如果哈希表中不存在,则将当前数以及下标分别存到哈希表的Key和Value上}return new int[0];//如果遍历完数组,还是没找到结果,则返回空数组}
}

时间复杂度为O(n),n为数组的长度,遍历数组耗费O(n)的时间
空间复杂度为O(n),哈希表最大存储空间

第2题 两数相加(中等)

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入 输出
l1 = [2,4,3], l2 = [5,6,4] [7,0,8]

解释:342 + 465 = 807.

示例 2:

输入 输出
l1 = [0], l2 = [0] [0]

示例 3:

输入 输出
l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] [8,9,9,9,0,0,0,1]

代码

// 两数相加:链表
class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode pre = new ListNode(0);//建立新链表ListNode cur = pre;//当前节点int carry=0;//进位值while(l1 != null || l2 != null){//判断是否遍历完两个链表int x = l1 != null ? l1.val : 0;//l1未遍历完,则取它的值int y = l2 != null ? l2.val : 0;//同理int sum = x + y + carry;//两个链表的节点值加进位值carry = sum / 10;//新的进位值sum %= 10;//新链表的节点值cur.next = new ListNode(sum);//将节点值插入新链表cur = cur.next;//指针指向下一位置if(l1 != null)//判断是否遍历完l1l1 = l1.next;if(l2 != null)//同理l2 = l2.next;}if(carry != 0){//如果遍历完了两个链表,还存在进位,则将进位值加入新链表cur.next = new ListNode(carry);}return pre.next;}
}

时间复杂度为O(max(m,n)),m,n为两个链表的长度
空间复杂度为O(1)

第3题 无重复字符的最长子串(中等)

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入 输出
s = “abcabcbb” 3

解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

示例 2:

输入 输出
s = “bbbbb” 1

解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

示例 3:

输入 输出
s = “pwwkew” 3

解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

示例 4:

输入 输出
s = “” 0

代码

// 无重复字符的最长子串:滑动窗口
class Solution {public int lengthOfLongestSubstring(String s) {Set<Character> occ = new HashSet<Character>();//建立哈希集合int n = s.length();        int rk = -1, ans = 0;// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动for (int i = 0; i < n; ++i) {if (i != 0) {                occ.remove(s.charAt(i - 1));// 左指针向右移动一格,移除一个字符}while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {//哈希集合中不存在当前字符                occ.add(s.charAt(rk + 1));// 不断地移动右指针++rk;}ans = Math.max(ans, rk - i + 1);//如果遇到重复字符,则先退出去比较长度}return ans;}
}

时间复杂度为O(n),n为字符串的长度
空间复杂度为O(∣Σ∣),Σ为字符集的大小,哈希集合存储大小

第4题 寻找两个正序数组的中位数(困难)

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

示例 1:

输入 输出
nums1 = [1,3], nums2 = [2] 2.00000

解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入 输出
nums1 = [1,2], nums2 = [3,4] 2.50000

解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:

输入 输出
nums1 = [0,0], nums2 = [0,0] 0.00000

示例 4:

输入 输出
nums1 = [], nums2 = [1] 1.00000

示例 5:

输入 输出
nums1 = [2], nums2 = [] 2.00000

代码

// 寻找两个正序数组的中位数:二分查找
class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {//寻找中位数int length1 = nums1.length, length2 = nums2.length;int totalLength = length1 + length2;if (totalLength % 2 == 1) {//两个数组相加为奇数int midIndex = totalLength / 2;//两个数组元素个数的一半double median = getKthElement(nums1, nums2, midIndex + 1);return median;} else {//为偶数时int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;//求两个相邻元素和的一半return median;}}public int getKthElement(int[] nums1, int[] nums2, int k) {//得到第k个元素int length1 = nums1.length, length2 = nums2.length;int index1 = 0, index2 = 0;int kthElement = 0;while (true) {if (index1 == length1) {//数组1为空return nums2[index2 + k - 1];}if (index2 == length2) {//数组2为空return nums1[index1 + k - 1];}if (k == 1) {//中间数为1,则返回最小的数组中的值return Math.min(nums1[index1], nums2[index2]);}            int half = k / 2;int newIndex1 = Math.min(index1 + half, length1) - 1;int newIndex2 = Math.min(index2 + half, length2) - 1;//找到各自矩阵的最小值int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];if (pivot1 <= pivot2) {//比较两个数组当前值(从最小值开始比较)k -= (newIndex1 - index1 + 1);//如果数组二大。则k减去索引index1 = newIndex1 + 1;//变更数组1为下一个值} else {//同理,直到k为0k -= (newIndex2 - index2 + 1);index2 = newIndex2 + 1;}}}
}

时间复杂度为O(log(m+n)),m和n为数组nums1和nums2的长度
空间复杂度为O(1)

第5题 最长回文子串(中等)

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入 输出
s = “babad” “bab”

示例 2:

输入 输出
s = “cbbd” “bb”

示例 3:

输入 输出
s = “a” “a”

示例 4:

输入 输出
s = “ac” “a”

代码

// 最长回文子串:双指针
class Solution {public String longestPalindrome(String s) {if (s == null || s.length() < 1) {return "";}int start = 0, end = 0;for (int i = 0; i < s.length(); i++) {int len1 = expandAroundCenter(s, i, i);//中间有单个字符的回文串int len2 = expandAroundCenter(s, i, i + 1);//中间无单个字符的回文串int len = Math.max(len1, len2);//找到最大长度if (len > end - start) {//如果最大长度比字符串首尾位置差还大start = i - (len - 1) / 2;//则起点为首位end = i + len / 2;//终点位末位}}return s.substring(start, end + 1);//将从起点到结尾的字符输出}public int expandAroundCenter(String s, int left, int right) {//中心扩展while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {//如果左右指针在字符串内且左右指针所指的值一样--left;++right;//则左指针左移,右指针右移}return right - left - 1;//直到左右出范围或者左右指针所指字符不等,则返回左右指针之间的距离}
}

时间复杂度为O(n2n^2n2),n为字符串的长度
空间复杂度为O(1)

第10题 正则表达式匹配(困难)

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
’ * ’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入 输出
s = “aa” p = “a” false

解释:“a” 无法匹配 “aa” 整个字符串。

示例 2:

输入 输出
输入:s = “ab” p = “.*” true

示例 3:

输入 输出
s = “aa” p = “a*” true

解释:因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。

示例 4:

输入 输出
输入:s = “aab” p = “cab” true

解释:因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。

示例 5:

输入 输出
s = “mississippi” p = “misisp*.” false

代码

// 正则表达式匹配:动态规划
class Solution {public boolean isMatch(String s, String p) {int m = s.length();int n = p.length();boolean[][] f = new boolean[m + 1][n + 1];f[0][0] = true;for (int i = 0; i <= m; ++i) {for (int j = 1; j <= n; ++j) {if (p.charAt(j - 1) == '*') {//如果p中第j-1个字符是*,则可以匹配多次f[i][j] = f[i][j - 2];//对p中第j-1个字符匹配多次,匹配0次的情况if (matches(s, p, i, j - 1)) {//判断匹配f[i][j] = f[i][j] || f[i - 1][j];//如果符合,则字符串s中前i个字符和字符串p中前j个字符是否匹配取决于前一个i和当前的i是否匹配}} else {if (matches(s, p, i, j)) {//如果p的第j个字符是一个小写字母f[i][j] = f[i - 1][j - 1];//则是否匹配取决于i-1和j-1}}}}return f[m][n];}public boolean matches(String s, String p, int i, int j) {//匹配判断if (i == 0) {return false;}if (p.charAt(j - 1) == '.') {//出现‘.’代表匹配return true;}return s.charAt(i - 1) == p.charAt(j - 1);//字符是否匹配}
}

时间复杂度为O(mn),m和n分别为字符串s和p的长度
空间复杂度为O(mn)

第11题 盛最多水的容器(中等)

给你 n 个非负整数 a1,a2,...,an,a_1,a_2,...,a_n,a1​,a2​,...,an​,每个数代表坐标中的一个点 (i, aia_iai​) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, aia_iai​) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。

示例 1:

输入 输出
[1,8,6,2,5,4,8,3,7] 49

解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入 输出
height = [1,1] 1

示例 3:

输入 输出
height = [4,3,2,1,4] 16

示例 4:

输入 输出
height = [1,2,1] 2

代码

// 盛最多水的容器:双指针
public class Solution {public int maxArea(int[] height) {int l = 0, r = height.length - 1;//定义双指针,指向首尾int ans = 0;while (l < r) {int area = Math.min(height[l], height[r]) * (r - l);//比较高度,找出左右边界最低的高度,然后乘上左右边界之间的距离ans = Math.max(ans, area);if (height[l] <= height[r]) {//比较左右边界高度++l;//左边低,左指针右移}else {--r;//右边低,右指针左移}}return ans;}
}

时间复杂度为O(n),n为数组的长度
空间复杂度为O(1)

第15题 三数之和(中等)

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:

输入 输出
nums = [-1,0,1,2,-1,-4] [[-1,-1,2],[-1,0,1]]

示例 2:

输入 输出
nums = [] []

示例 3:

输入 输出
nums = [0] []

代码

// 三数之和:排序 + 双指针
class Solution {public List<List<Integer>> threeSum(int[] nums) {int n = nums.length;Arrays.sort(nums);//排序List<List<Integer>> ans = new ArrayList<List<Integer>>();for (int first = 0; first < n; ++first) {//第一个数if (first > 0 && nums[first] == nums[first - 1]) {//当first大于0且相邻两个数相等时,跳过continue;}int third = n - 1;//第三个数int target = -nums[first];//目标值for (int second = first + 1; second < n; ++second) {//第二个数在第一个数之后if (second > first + 1 && nums[second] == nums[second - 1]) {//如果第二个数在第一个数后一个位置以后,且相邻两个数相等时,跳过continue;}while (second < third && nums[second] + nums[third] > target) {//如果第二个数加第三个数大于目标值,则第三个数右移--third;}if (second == third) {//如果第二个数等于第三个数,则终止本层循环break;}if (nums[second] + nums[third] == target) {//如果第二个数和第三个数相加等于目标值,则输出结果List<Integer> list = new ArrayList<Integer>();list.add(nums[first]);list.add(nums[second]);list.add(nums[third]);ans.add(list);}}}return ans;}
}

时间复杂度为O(N2N^2N2),n为数组的长度
空间复杂度为O(log⁡N\log NlogN)

第17题 电话号码的字母组合(中等)

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例 1:

输入 输出
digits = “23” [“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

示例 2:

输入 输出
digits = “” []

示例 3:

输入 输出
digits = “2” [“a”,“b”,“c”]

代码

// 电话号码的字母组合:回溯
class Solution {public List<String> letterCombinations(String digits) {List<String> combinations = new ArrayList<String>();if (digits.length() == 0) { //输入的数字为0return combinations;}Map<Character, String> phoneMap = new HashMap<Character, String>() {{ //建立哈希地图,存储各数字及其对应字母put('2', "abc");put('3', "def");put('4', "ghi");put('5', "jkl");put('6', "mno");put('7', "pqrs");put('8', "tuv");put('9', "wxyz");}};backtrack(combinations, phoneMap, digits, 0, new StringBuffer()); //回溯return combinations;}public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {if (index == digits.length()) {combinations.add(combination.toString());} else {char digit = digits.charAt(index);String letters = phoneMap.get(digit);int lettersCount = letters.length();for (int i = 0; i < lettersCount; i++) { //在前一个字母后追加新字母combination.append(letters.charAt(i));backtrack(combinations, phoneMap, digits, index + 1, combination); //调用回溯combination.deleteCharAt(index); //删除当前索引}}}
}

时间复杂度为O(3m×4n3^m×4^n3m×4n),n为数组的长度
空间复杂度为O(m+nm+nm+n)

第19题 删除链表的倒数第 N 个结点(中等)

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

输入 输出
head = [1,2,3,4,5], n = 2 [1,2,3,5]

示例 2:

输入 输出
head = [1,2], n = 1 [1]

示例 3:

输入 输出
head = [1], n = 1 []

代码

//删除链表的倒数第 N 个结点:双指针
class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummy = new ListNode(0, head);ListNode first = head;ListNode second = dummy;//构造双指针for (int i = 0; i < n; ++i) {first = first.next; //让第一个指针向后便利到第n个节点}while (first != null) {first = first.next; //让第一个指针遍历到末尾second = second.next; //同时让第二个节点往后遍历到倒数第n个节点处}second.next = second.next.next; //删除倒数第n个节点ListNode ans = dummy.next;return ans;}
}

时间复杂度为O(LLL),L为链表的长度
空间复杂度为O(111)

第20题 有效的括号(简单)

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

示例 1:

输入 输出
s = “()” true

示例 2:

输入 输出
s = “()[]{}” true

示例 3:

输入 输出
s = “(]” false

示例 4:

输入 输出
s = “([)]” false

示例 5:

输入 输出
s = “{[]}” true

代码

//有效的括号:栈
class Solution {public boolean isValid(String s) {int n = s.length();if(n % 2 == 1){return false;}Map<Character,Character> pairs = new HashMap<Character,Character>(){{ //建立哈希表存储3种不同的括号类型put(')','(');put(']','[');put('}','{');}};Deque<Character> stack = new LinkedList<Character>();for(int i = 0;i < n;i++){char ch = s.charAt(i);if(pairs.containsKey(ch)){ //判断哈希表中是否存在当前的字符if(stack.isEmpty() || stack.peek() != pairs.get(ch)){ //如果存在当前字符,再判断栈是否为空,栈顶元素是否等于当前元素在哈希表中对应的值return false; //如果栈为空或者栈顶元素不等于当前元素在哈希表中对应的值,则返回false}stack.pop(); //否则将栈顶元素出栈}else{stack.push(ch); //如果哈希表中不存在当前字符,则将当前元素入栈}}return stack.isEmpty(); //最后返回栈是否为空}
}

时间复杂度为O(nnn),n为字符串s的长度
空间复杂度为O(n+∣Σ∣n+∣Σ∣n+∣Σ∣)
,其中Σ 表示字符集,本题中字符串只包含 6 种括号,∣Σ∣=6。

第21题 合并两个有序链表(简单)

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

示例 1:

输入 输出
l1 = [1,2,4], l2 = [1,3,4] [1,1,2,3,4,4]

示例 2:

输入 输出
l1 = [], l2 = [] []

示例 3:

输入 输出
l1 = [], l2 = [0] [0]

代码

//合并两个有序链表:迭代
class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode prehead = new ListNode(-1);ListNode prev = prehead;while (l1 != null && l2 != null) { //判断列表是否为空if (l1.val <= l2.val) { //比较两链表当前节点值,将小的值插入新链表后,并向后移动指针prev.next = l1;l1 = l1.next;} else {prev.next = l2;l2 = l2.next;}prev = prev.next;}// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可prev.next = l1 == null ? l2 : l1;return prehead.next;}
}

时间复杂度为O(n+mn+mn+m),n和m分别为两个链表的长度
空间复杂度为O(111)

第22题 括号生成(中等)

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
有效括号组合需满足:左括号必须以正确的顺序闭合。

示例 1:

输入 输出
n = 3 ["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入 输出
n = 1 ["()"]

示例 3:

输入 输出
l1 = [], l2 = [0] [0]

代码

//括号生成:回溯
class Solution {public List<String> generateParenthesis(int n) {List<String> ans = new ArrayList<String>();backtrack(ans, new StringBuilder(), 0, 0, n);return ans;}public void backtrack(List<String> ans, StringBuilder cur, int open, int close, int max) {  //回溯if (cur.length() == max * 2) {  //括号数为给定数字的2倍ans.add(cur.toString());return;}if (open < max) { //添加左括号cur.append('(');backtrack(ans, cur, open + 1, close, max); //回溯cur.deleteCharAt(cur.length() - 1); //剪枝}if (close < open) { //添加右括号cur.append(')');backtrack(ans, cur, open, close + 1, max); //回溯cur.deleteCharAt(cur.length() - 1); //剪枝}}
}

时间复杂度为O(4nn\frac{4^n}{\sqrt n}n​4n​),n为数字大小
空间复杂度为O(nnn)

第23题 合并K个升序链表(困难)

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入 输出
lists = [[1,4,5],[1,3,4],[2,6]] [1,1,2,3,4,4,5,6]

解释:链表数组如下:
[1->4->5,1->3->4,2->6]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入 输出
lists = [] []

示例 3:

输入 输出
lists = [[ ]] []

代码

//合并K个升序链表:分治
class Solution {public ListNode mergeKLists(ListNode[] lists) {return merge(lists, 0, lists.length - 1);}public ListNode merge(ListNode[] lists, int l, int r) { //判断是否归并完if (l == r) {return lists[l]; //归并到了同一个链表,则返回这个链表}if (l > r) { //左大于右代表遍历完了return null;}int mid = (l + r) >> 1;return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r)); //调用归并2个链表算法}public ListNode mergeTwoLists(ListNode a, ListNode b) { //归并2个链表if (a == null || b == null) { //判断两链表是否有为空的return a != null ? a : b; //有的话返回另一个不为空的链表}ListNode head = new ListNode(0);ListNode tail = head, aPtr = a, bPtr = b;while (aPtr != null && bPtr != null) { //如果两个链表不为空,则将tail链表的下一节点指向值小的链表if (aPtr.val < bPtr.val) {tail.next = aPtr;aPtr = aPtr.next;} else {tail.next = bPtr;bPtr = bPtr.next;}tail = tail.next;}tail.next = (aPtr != null ? aPtr : bPtr);return head.next;}
}

时间复杂度为O(kn×logkkn×logkkn×logk),k为链表数,n为链表内数字数量
空间复杂度为O(logklogklogk)

第31题 下一个排列(中等)

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。

示例 1:

输入 输出
nums = [1,2,3] [1,3,2]

示例 2:

输入 输出
nums = [3,2,1] [1,2,3]

示例 3:

输入 输出
nums = [1,1,5] [1,5,1]

示例 4:

输入 输出
nums = [1] [1]

代码

//下一个排列:数组
class Solution {public void nextPermutation(int[] nums) {int i = nums.length - 2;while (i >= 0 && nums[i] >= nums[i + 1]) { //判断数组最后两个数字的关系,如果前一个数字大于后一个数字,则向前遍历i--;}if (i >= 0) {int j = nums.length - 1;while (j >= 0 && nums[i] >= nums[j]) { //将前一个位置i的值与最后一个数相比较,如果后面的数小,则从最后一个数开始向前遍历,直到找到一个比前一个数大的数j--;}swap(nums, i, j); //交换}reverse(nums, i + 1); //翻转}public void swap(int[] nums, int i, int j) { //交换位置i和位置j的值int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}public void reverse(int[] nums, int start) { //翻转int left = start, right = nums.length - 1;while (left < right) {swap(nums, left, right);left++;right--;}}
}

时间复杂度为O(nnn),n为数组长度
空间复杂度为O(111)

第32题 最长有效括号(困难)

给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入 输出
s = “(()” 2

解释:最长有效括号子串是 “()”

示例 2:

输入 输出
s = “)()())” 4

解释:最长有效括号子串是 “()()”

示例 3:

输入 输出
s = “” 0

代码

//最长有效括号:动态规划
class Solution {public int longestValidParentheses(String s) {int maxans = 0;int[] dp = new int[s.length()];for (int i = 1; i < s.length(); i++) {if (s.charAt(i) == ')') { //找到以‘)’结尾的位置if (s.charAt(i - 1) == '(') { //如果它前面的位置为‘(’dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; //记录当前位置的有效括号数} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { //如果前一个位置为‘)’,再判断前一个是否为‘(’dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; //如果是‘(’,则记录前一个位置的有效括号数加上当前的括号数}maxans = Math.max(maxans, dp[i]); //存储最长有效括号数}}return maxans;}
}

时间复杂度为O(nnn),n为字符串的长度
空间复杂度为O(nnn)

第33题 搜索旋转排序数组(中等)

整数数组 nums 按升序排列,数组中的值 互不相同 。在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

示例 1:

输入 输出
nums = [4,5,6,7,0,1,2], target = 0 4

示例 2:

输入 输出
nums = [4,5,6,7,0,1,2], target = 3 -1

示例 3:

输入 输出
nums = [1], target = 0 -1

代码

//搜索旋转排序数组:二分查找
class Solution {public int search(int[] nums, int target) {int n = nums.length;if (n == 0) { //判断数组大小是否为0或者1return -1;}if (n == 1) {return nums[0] == target ? 0 : -1;}int l = 0, r = n - 1; //设立左右端点while (l <= r) {int mid = (l + r) / 2; //设立中间点if (nums[mid] == target) { //判断中间点是否为目标值return mid;}if (nums[0] <= nums[mid]) { //如果数组第一个值比中间值小,且左端点小于目标值,目标值小于中间值,则令右端点等于中间点前一个点if (nums[0] <= target && target < nums[mid]) {r = mid - 1;} else { //否则令左端点等于中间的后一个点l = mid + 1;}} else { //如果目标值在在中间点与数组最后一个值之间if (nums[mid] < target && target <= nums[n - 1]) {l = mid + 1;} else {r = mid - 1;}}}return -1; //如果没有找到结果。则返回-1}
}

时间复杂度为O(lognlognlogn),n为数组的长度
空间复杂度为O(111)

第34题 在排序数组中查找元素的第一个和最后一个位置(中等)

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。

示例 1:

输入 输出
nums = [5,7,7,8,8,10], target = 8 [3,4]

示例 2:

输入 输出
nums = [5,7,7,8,8,10], target = 6 [-1,-1]

示例 3:

输入 输出
nums = [], target = 0 [-1,-1]

代码

//在排序数组中查找元素的第一个和最后一个位置:二分查找
class Solution {public int[] searchRange(int[] nums, int target) {int leftIdx = binarySearch(nums, target, true); //查找目标元素出现的第一个位置int rightIdx = binarySearch(nums, target, false) - 1; //查找目标元素出现的最后一个位置if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {return new int[]{leftIdx, rightIdx}; //如果第一个位置等于最后一个位置或者在最后一个位置之前,则返回这两个位置} return new int[]{-1, -1}; //否则返回-1}public int binarySearch(int[] nums, int target, boolean lower) { //二分查找int left = 0, right = nums.length - 1, ans = nums.length;while (left <= right) { int mid = (left + right) / 2;if (nums[mid] > target || (lower && nums[mid] >= target)) { //如果目标值小于中间值,则让右端点等于中间点前一个点,结果等于中间点right = mid - 1;ans = mid;} else { //否则让左端点等于中间点后一个位置left = mid + 1;}}return ans;}
}

时间复杂度为O(lognlognlogn),n为数组的长度
空间复杂度为O(111)

第39题 组合总和(中等)

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。

示例 1:

输入 输出
candidates = [2,3,6,7], target = 7 [[7],[2,2,3]]

示例 2:

输入 输出
candidates = [2,3,5], target = 8 [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入 输出
candidates = [2], target = 1 []

示例 4:

输入 输出
candidates = [1], target = 1 [[1]]

示例 5:

输入 输出
candidates = [1], target = 2 [[1,1]]

代码

//组合总和:回溯
class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> ans = new ArrayList<List<Integer>>();List<Integer> combine = new ArrayList<Integer>();dfs(candidates, target, ans, combine, 0); //深搜return ans;}public void dfs(int[] candidates, int target, List<List<Integer>> ans, List<Integer> combine, int idx) {if (idx == candidates.length) {return;}if (target == 0) {ans.add(new ArrayList<Integer>(combine));return;}// 直接跳过dfs(candidates, target, ans, combine, idx + 1);// 选择当前数if (target - candidates[idx] >= 0) {combine.add(candidates[idx]); //将可行的解加入数组中dfs(candidates, target - candidates[idx], ans, combine, idx);combine.remove(combine.size() - 1); //剪枝}}
}

时间复杂度为O(SSS),S为所有可行解的长度和
空间复杂度为O(targettargettarget)

第42题 接雨水(困难)

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。

示例 1:

输入 输出
height = [0,1,0,2,1,0,1,3,2,1,2,1] 6

解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入 输出
height = [4,2,0,3,2,5] 9

代码

//接雨水:双指针
class Solution {public int trap(int[] height) {int left = 0, right = height.length - 1;int ans = 0;int left_max = 0, right_max = 0;while (left < right) {if (height[left] < height[right]) {if (height[left] >= left_max) {left_max = height[left];} else {ans += (left_max - height[left]);}++left;} else {if (height[right] >= right_max) {right_max = height[right];} else {ans += (right_max - height[right]);}--right;}}return ans;
}
}

时间复杂度为O(nnn),n为数组长度
空间复杂度为O(111)

第46题 全排列(中等)

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入 输出
nums = [1,2,3] [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入 输出
nums = [0,1] [[0,1],[1,0]]

示例 3:

输入 输出
nums = [1] [[1]]

代码

//全排列:回溯
class Solution {public List<List<Integer>> permute(int[] nums) {List<List<Integer>> res = new ArrayList<List<Integer>>();List<Integer> output = new ArrayList<Integer>();for (int num : nums) {output.add(num); //向数组列表中加入给定数组含有的数字}int n = nums.length;backtrack(n, output, res, 0);  //回溯return res; }public void backtrack(int n, List<Integer> output, List<List<Integer>> res, int first) { //回溯if (first == n) {  // 所有数都填完了res.add(new ArrayList<Integer>(output));}for (int i = first; i < n; i++) {Collections.swap(output, first, i);  backtrack(n, output, res, first + 1);  //回溯调用下一个数Collections.swap(output, first, i);   // 剪枝}}
}

时间复杂度为O(n×n!n×n!n×n!),n为序列长度
空间复杂度为O(nnn)

第49题 字母异位词分组(中等)

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母都恰好只用一次。

示例 1:

输入 输出
strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]

示例 2:

输入 输出
strs = [""] [[""]]

示例 3:

输入 输出
strs = [“a”] [[“a”]]

代码

//字母异位词分组:哈希表
class Solution {public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> map = new HashMap<String, List<String>>(); //构造哈希表for (String str : strs) {char[] array = str.toCharArray();Arrays.sort(array); //排序String key = new String(array);List<String> list = map.getOrDefault(key, new ArrayList<String>());list.add(str);map.put(key, list); //将相同字母的单词存放在一起}return new ArrayList<List<String>>(map.values());}
}

时间复杂度为O(nklogknklogknklogk),n为字符串的数量,k为字符串的最大长度
空间复杂度为O(nknknk)

第53题 最大子序和(简单)

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:

输入 输出
nums = [-2,1,-3,4,-1,2,1,-5,4] 6

示例 2:

输入 输出
nums = [1] 1

示例 3:

输入 输出
nums = [0] 0

示例 4:

输入 输出
nums = [-1] -1

示例 5:

输入 输出
nums = [-100000] -100000

代码

//最大子序和:动态规划
class Solution {public int maxSubArray(int[] nums) {int pre = 0, maxAns = nums[0];for (int x : nums) {pre = Math.max(pre + x, x); //滚动窗口maxAns = Math.max(maxAns, pre);}return maxAns;}
}

时间复杂度为O(nnn),n为数组的长度
空间复杂度为O(111)

第55题 跳跃游戏(中等)

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。

示例 1:

输入 输出
nums = [2,3,1,1,4] true

解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入 输出
nums = [3,2,1,0,4] false

解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

代码

//跳跃游戏:贪心
public class Solution {public boolean canJump(int[] nums) {int n = nums.length;int rightmost = 0; //最远距离for (int i = 0; i < n; ++i) {if (i <= rightmost) {rightmost = Math.max(rightmost, i + nums[i]);  //取最大值if (rightmost >= n - 1) { //判断是否能到最后一个点return true;}}}return false;}
}

时间复杂度为O(nnn),n为数组的长度
空间复杂度为O(111)

第56题 合并区间(中等)

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti,endistart_i, end_istarti​,endi​] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:

输入 输出
intervals = [[1,3],[2,6],[8,10],[15,18]] [[1,6],[8,10],[15,18]]

解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入 输出
intervals = [[1,4],[4,5]] [[1,5]]

解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

代码

//合并区间:排序
class Solution {public int[][] merge(int[][] intervals) {if (intervals.length == 0) {return new int[0][2];}Arrays.sort(intervals, new Comparator<int[]>() { //排序,数组中第一个数字按从小到大排public int compare(int[] interval1, int[] interval2) {return interval1[0] - interval2[0];}});List<int[]> merged = new ArrayList<int[]>(); //构建合并列表for (int i = 0; i < intervals.length; ++i) {int L = intervals[i][0], R = intervals[i][1]; //L为各区间的左区间,R为各区间的右区间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()][]);}
}

时间复杂度为O(nlognnlognnlogn),n为区间的数量
空间复杂度为O(lognlognlogn)

第62题 不同路径(中等)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?

示例 1:

输入 输出
m = 3, n = 7 28

示例 2:

输入 输出
m = 3, n = 2 3

解释:
从左上角开始,总共有 3 条路径可以到达右下角。1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

示例 3:

输入 输出
m = 7, n = 3 28

示例 4:

输入 输出
m = 3, n = 3 6

代码

//不同路径:动态规划
class Solution {public int uniquePaths(int m, int n) {int[][] f = new int[m][n];for (int i = 0; i < m; ++i) {  //令第一行和第一列的路径数都为1f[i][0] = 1;}for (int j = 0; j < n; ++j) {f[0][j] = 1;}for (int i = 1; i < m; ++i) {for (int j = 1; j < n; ++j) {f[i][j] = f[i - 1][j] + f[i][j - 1]; //除第一行和第一列的其他行列的路径数等于上一行该列的路径数加上该行上一列的路径数}}return f[m - 1][n - 1];}
}

时间复杂度为O(mnmnmn),m,n分别为行列数
空间复杂度为O(mnmnmn)

第64题 最小路径和(中等)

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。

示例 1:

输入 输出
grid = [[1,3,1],[1,5,1],[4,2,1]] 7

解释:因为路径 1→3→1→1→1 的总和最小。

示例 2:

输入 输出
grid = [[1,2,3],[4,5,6]] 12

代码

//最小路径和:动态规划
class Solution {public int minPathSum(int[][] grid) {if (grid == null || grid.length == 0 || grid[0].length == 0) {return 0;}int rows = grid.length, columns = grid[0].length;int[][] dp = new int[rows][columns];dp[0][0] = grid[0][0];for (int i = 1; i < rows; i++) {dp[i][0] = dp[i - 1][0] + grid[i][0]; //计算一列的值}for (int j = 1; j < columns; j++) { //计算第一行的值dp[0][j] = dp[0][j - 1] + grid[0][j];}for (int i = 1; i < rows; i++) {for (int j = 1; j < columns; j++) {dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; //其他行列的值等于上一行与上一列的最小值加上当前的值}}return dp[rows - 1][columns - 1];}
}

时间复杂度为O(mnmnmn),m,n分别为行列数
空间复杂度为O(mnmnmn)

第70题 爬楼梯(简单)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入 输出
2 2

解释: 有两种方法可以爬到楼顶。1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入 输出
3 3

解释: 有三种方法可以爬到楼顶。1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

代码

//爬楼梯:动态规划
class Solution {public int climbStairs(int n) {int p = 0, q = 0, r = 1;for (int i = 1; i <= n; ++i) {p = q;  //类似斐波那契数列q = r; r = p + q;}return r;}
}

时间复杂度为O(nnn),n为给定数字大小
空间复杂度为O(111)

第72题 编辑距离(困难)

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符

示例 1:

输入 输出
word1 = “intention”, word2 = “execution” 5

解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)

示例 2:

输入 输出
word1 = “horse”, word2 = “ros” 3

解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)

代码

//编辑距离:动态规划
class Solution {public int minDistance(String word1, String word2) {int n = word1.length();int m = word2.length();// 有一个字符串为空串if (n * m == 0) {return n + m;}// DP 数组int[][] D = new int[n + 1][m + 1];// 边界状态初始化for (int i = 0; i < n + 1; i++) {D[i][0] = i;}for (int j = 0; j < m + 1; j++) {D[0][j] = j;}// 计算所有 DP 值for (int i = 1; i < n + 1; i++) {for (int j = 1; j < m + 1; j++) {int left = D[i - 1][j] + 1;int down = D[i][j - 1] + 1;int left_down = D[i - 1][j - 1];if (word1.charAt(i - 1) != word2.charAt(j - 1)) {left_down += 1;}D[i][j] = Math.min(left, Math.min(down, left_down));}}return D[n][m];}
}

时间复杂度为O(mnmnmn),m,n分别为两字符串的长度
空间复杂度为O(mnmnmn)

第75题 颜色分类(中等)

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

示例 1:

输入 输出
nums = [2,0,2,1,1,0] [0,0,1,1,2,2]

示例 2:

输入 输出
nums = [2,0,1] [0,1,2]

示例 3:

输入 输出
nums = [0] [0]

示例 4:

输入 输出
nums = [1] [1]

代码

//颜色分类:双指针
class Solution {public void sortColors(int[] nums) {int n = nums.length;int p0 = 0, p2 = n - 1; //设立左右双指针for (int i = 0; i <= p2; ++i) {while (i <= p2 && nums[i] == 2) {  //如果当前遍历的值为2,则与右指针交换,然后右指针左移一位int temp = nums[i];nums[i] = nums[p2];nums[p2] = temp;--p2;}if (nums[i] == 0) { //如果当前遍历的值等于0,则与左指针交换,然后左指针右移一位int temp = nums[i];nums[i] = nums[p0];nums[p0] = temp;++p0;}}}
}

时间复杂度为O(nnn),n为数组长度
空间复杂度为O(111)

第76题 最小覆盖子串(困难)

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

示例 1:

输入 输出
s = “ADOBECODEBANC”, t = “ABC” “BANC”

示例 2:

输入 输出
s = “a”, t = “a” “a”

示例 3:

输入 输出
s = “a”, t = “aa” “”

解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

代码

//最小覆盖子串:滑动窗口
class Solution {Map<Character, Integer> ori = new HashMap<Character, Integer>();Map<Character, Integer> cnt = new HashMap<Character, Integer>();public String minWindow(String s, String t) {int tLen = t.length();for (int i = 0; i < tLen; i++) {char c = t.charAt(i);ori.put(c, ori.getOrDefault(c, 0) + 1);}int l = 0, r = -1;int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;int sLen = s.length();while (r < sLen) {++r;if (r < sLen && ori.containsKey(s.charAt(r))) {cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);}while (check() && l <= r) {if (r - l + 1 < len) {len = r - l + 1;ansL = l;ansR = l + len;}if (ori.containsKey(s.charAt(l))) {cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);}++l;}}return ansL == -1 ? "" : s.substring(ansL, ansR);}public boolean check() {Iterator iter = ori.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Character key = (Character) entry.getKey(); Integer val = (Integer) entry.getValue(); if (cnt.getOrDefault(key, 0) < val) {return false;}} return true;}
}

时间复杂度为O(C⋅∣s∣+∣t∣C⋅∣s∣+∣t∣C⋅∣s∣+∣t∣),C为字符集的大小,s,t为给定字符串长度
空间复杂度为O(CCC)

第78题 子集(中等)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入 输出
nums = [1,2,3] [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入 输出
nums = [0] [[],[0]]

代码

//子集:数学
class Solution {List<Integer> t = new ArrayList<Integer>();List<List<Integer>> ans = new ArrayList<List<Integer>>();public List<List<Integer>> subsets(int[] nums) {int n = nums.length;for (int mask = 0; mask < (1 << n); ++mask) { //1<<n代表2的n-1次方t.clear();for (int i = 0; i < n; ++i) {if ((mask & (1 << i)) != 0) { //将各种可能性都算上t.add(nums[i]);}}ans.add(new ArrayList<Integer>(t));}return ans;}
}

时间复杂度为O(n∗n2n*n^2n∗n2),一共有2n2^n2n个状态,每个状态需要O(n)的时间构建子集
空间复杂度为O(nnn)

第79题 单词搜索(中等)

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

输入 输出
board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED” true

示例 2:

输入 输出
board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE” true

示例 3:

输入 输出
board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB” false

代码

//单词搜索:回溯
class Solution {public boolean exist(char[][] board, String word) {int h = board.length, w = board[0].length;boolean[][] visited = new boolean[h][w];for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {boolean flag = check(board, visited, i, j, word, 0);//判断从i,j位置出发是否能找到对应的单词if (flag) {return true;}}}return false;}public boolean check(char[][] board, boolean[][] visited, int i, int j, String s, int k) {if (board[i][j] != s.charAt(k)) {//字符串字母不匹配return false;} else if (k == s.length() - 1) {//匹配完成return true;}visited[i][j] = true;int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};//相邻位置boolean result = false;for (int[] dir : directions) {int newi = i + dir[0], newj = j + dir[1];//搜索相邻位置if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {//判断是否越位if (!visited[newi][newj]) {boolean flag = check(board, visited, newi, newj, s, k + 1);//搜索判断是否符合if (flag) {result = true;break;}}}}visited[i][j] = false;return result;}
}

时间复杂度为O(MN⋅3LMN⋅3^LMN⋅3L),M,N为网格的长和宽,L为字符串的长度
空间复杂度为O(MNMNMN)

第84题 柱状图中最大的矩形(困难)

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

输入 输出
heights = [2,1,5,6,2,3] 10

示例 2:

输入 输出
heights = [2,4] 4

代码

//柱状图中最大的矩形:栈
class Solution {public int largestRectangleArea(int[] heights) {int n = heights.length;int[] left = new int[n];//左指针int[] right = new int[n];//右指针Arrays.fill(right, n);  //在右指针处填数组长度  Deque<Integer> mono_stack = new ArrayDeque<Integer>();//搭建栈for (int i = 0; i < n; ++i) {while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {//如果栈不为空且栈顶元素的高度大于当前元素的高度right[mono_stack.peek()] = i;//则右指针的栈顶元素值为imono_stack.pop();//栈顶元素出栈}left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());//左指针的值为栈顶元素mono_stack.push(i);//将第i个元素入栈}int ans = 0;for (int i = 0; i < n; ++i) {ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);//比较当前遍历到的元素的最大值}return ans;}
}

时间复杂度为O(nnn),n为数组长度
空间复杂度为O(nnn)

第85题 最大矩形(困难)

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例 1:

输入 输出
matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]] 6

示例 2:

输入 输出
matrix = [] 0

示例 3:

输入 输出
matrix = [[“0”]] 0

示例 4:

输入 输出
matrix = [[“1”]] 1

示例 5:

输入 输出
matrix = [[“0”,“0”]] 0

代码

//最大矩形:栈
class Solution {public int maximalRectangle(char[][] matrix) {int m = matrix.length;if (m == 0) {return 0;}int n = matrix[0].length;int[][] left = new int[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (matrix[i][j] == '1') { //判断当前遍历到的数是否为1left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;//如果不是第1列,则当前值为上一列的值加1}}}int ret = 0;for (int j = 0; j < n; j++) { // 对于每一列,使用基于柱状图的方法int[] up = new int[m];int[] down = new int[m];Deque<Integer> stack = new LinkedList<Integer>();for (int i = 0; i < m; i++) {while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {stack.pop();}up[i] = stack.isEmpty() ? -1 : stack.peek();stack.push(i);}stack.clear();for (int i = m - 1; i >= 0; i--) {while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {stack.pop();}down[i] = stack.isEmpty() ? m : stack.peek();stack.push(i);}for (int i = 0; i < m; i++) {int height = down[i] - up[i] - 1;int area = height * left[i][j];ret = Math.max(ret, area);}}return ret;}
}

时间复杂度为O(mnmnmn),m,n分别为数组的行列数
空间复杂度为O(mnmnmn)

第94题 二叉树的中序遍历(简单)

给定一个二叉树的根节点 root ,返回它的 中序 遍历。

示例 1:

输入 输出
root = [1,null,2,3]] [1,3,2]

示例 2:

输入 输出
root = [] []

示例 3:

输入 输出
root = [1,2] [2,1]

示例 4:

输入 输出
root = [1,null,2] [1,2]

代码

//二叉树的中序遍历:递归
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<Integer>();inorder(root, res);return res;}public void inorder(TreeNode root, List<Integer> res) {if (root == null) {return;}inorder(root.left, res);//左res.add(root.val);//中inorder(root.right, res);//右}
}

时间复杂度为O(nnn),n为二叉树的结点个数
空间复杂度为O(nnn)

第96题 不同的二叉搜索树(中等)

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入 输出
n = 3 5

示例 2:

输入 输出
n = 1 1

代码

//不同的二叉搜索树:动态规划
class Solution {public int numTrees(int n) {int[] G = new int[n + 1];G[0] = 1;G[1] = 1;for (int i = 2; i <= n; ++i) {for (int j = 1; j <= i; ++j) {G[i] += G[j - 1] * G[i - j];}}return G[n];}
}

时间复杂度为O(n2n^2n2),n为给定数字
空间复杂度为O(nnn)

第98题 验证二叉搜索树(中等)

给定一个二叉树,检查它是否是镜像对称的。

示例 1:

输入 输出
root = [2,1,3] true

示例 2:

输入 输出
root = [5,1,4,null,null,3,6] false

代码

//验证二叉搜索树:递归
class Solution {public boolean isValidBST(TreeNode root) {return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);}public boolean isValidBST(TreeNode node, long lower, long upper) {if (node == null) {return true;}if (node.val <= lower || node.val >= upper) {//判断当前节点值是否小于最小值或者大于最大值return false;}return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);}
}

时间复杂度为O(nnn),n为二叉树的结点个数
空间复杂度为O(nnn)

第101题 对称二叉树(简单)

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

示例 1:

输入 输出
[1,2,2,3,4,4,3] true

示例 2:

输入 输出
[1,2,2,null,3,null,3] false

代码

//对称二叉树:递归
class Solution {public boolean isSymmetric(TreeNode root) {return check(root, root);}public boolean check(TreeNode p, TreeNode q) {if (p == null && q == null) {return true;}if (p == null || q == null) {return false;}return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);//判断左右节点是否对称}
}

时间复杂度为O(nnn),n为二叉树的结点个数
空间复杂度为O(nnn)

第102题 二叉树的层序遍历(中等)

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

示例 1:

输入 输出
[3,9,20,null,null,15,7] [[3],[9,20],[15,7]]

代码

//二叉树的层序遍历:BFS
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ret = new ArrayList<List<Integer>>();if (root == null) {return ret;}Queue<TreeNode> queue = new LinkedList<TreeNode>();//建立队列queue.offer(root);while (!queue.isEmpty()) {List<Integer> level = new ArrayList<Integer>();int currentLevelSize = queue.size();for (int i = 1; i <= currentLevelSize; ++i) {TreeNode node = queue.poll();//出队level.add(node.val);//输出加上当前层次的结点值if (node.left != null) {queue.offer(node.left);//加入左结点}if (node.right != null) {queue.offer(node.right);//加入右结点}}ret.add(level);//结果中加入每一层次的节点值}return ret;}
}

时间复杂度为O(nnn),n为二叉树的结点个数
空间复杂度为O(nnn)

第104题 二叉树的最大深度(简单)

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

示例 1:

输入 输出
[3,9,20,null,null,15,7] 3

代码

//二叉树的最大深度:DFS
class Solution {public int maxDepth(TreeNode root) {if (root == null) {return 0;} else {int leftHeight = maxDepth(root.left);//遍历左子树int rightHeight = maxDepth(root.right);//遍历右子树return Math.max(leftHeight, rightHeight) + 1;}}
}

时间复杂度为O(nnn),n为二叉树的结点个数
空间复杂度为O(heightheightheight)
,height为二叉树的高度

LeetCode 热题 HOT 100相关推荐

  1. 《LeetCode 热题 HOT 100》Java答案汇总版---持续更新中

    <LeetCode 热题 HOT 100>Java答案汇总版-持续更新中 个人认为<LeetCode 热题 HOT 100>中的题目特别适合算法新手进行一个入门的刷题,而且作者 ...

  2. LeetCode 热题 HOT 100 完整题解笔记知识点分类 C++代码实现

    1.知识点分布 填一下这个之前欠的天坑,复习一下算法入门的经典基础题. 除夕,正月初一,初二,一共写了三整天,除了吃饭就窝着补题. 每天30题+,整个人都写晕啦,终于写完啦() markdown生成 ...

  3. LeetCode 热题 HOT 100 -------160. 相交链表(链表)206. 反转链表(递归、回溯)

    dsadas /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* L ...

  4. LeetCode 热题 HOT 100 第四十九天 152. 乘积最大子数组 中等题 用python3求解

    题目地址 给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积. 测试用例的答案是一个32-位整数. 子数组 是数组的连续子序 ...

  5. LeetCode 热题 HOT 100【题型归类汇总,助力刷题】

    介绍 对于算法题,按题型类别刷题才会更有成效,因此我这里在网上搜索并参考了下 "

  6. LeetCode 热题 HOT 100 -------31. 下一个排列(数组,数学问题)128. 最长连续序列(数组) 11. 盛最多水的容器(数组) 621. 任务调度器 (数组)

    dsadas /**思路:找下一个排列,并且尽可能小,所以我们应该找一序列中从左边开始的"较小值"与"较大值"交换,但是为了尽可能小应该满足: 1." ...

  7. 两数相加c++_LeetCode 热题 HOT 100(01,两数相加)

    LeetCode 热题 HOT 100(01,两数相加) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力,这也 ...

  8. Leetcode热题 二分法的主要应用(2)-夹逼准则

    持续刷题第13天 ! 今天我们继续刷Leetcode 热题 HOT 100,日复一日,相信自己,一定会有进步.如果一个人刷题太孤独了,欢迎加群每日一题算法群,让我们大家一起监督,一起成长. 此外我还建 ...

  9. Leetcode python《热题 HOT 100》15. 三数之和

    Leetcode python 之 <热题 HOT 100>:https://leetcode-cn.com/problemset/hot-100/ 15. 三数之和 给定一个包含 n 个 ...

最新文章

  1. css3加载中动画效果,CSS3实现加载中的动画效果
  2. 求一元二次方程(信息学奥赛一本通-T1058)
  3. linux gradle仓库位置,如何在Android Studio中使用Gradle发布项目至Jcenter仓库
  4. 为什么Kaggle不会让你成为一名出色的数据科学家?
  5. 分享一篇文章,博主的经历值得借鉴
  6. 第十篇、微信小程序-view组件
  7. 有什么软件可以把音频mp3格式转为文字?
  8. 绿竹生物冲刺港股:年期内亏损超5亿 泰格医药与北京亦庄是股东
  9. windows7系统:基本安装,U盘启动盘制作与安装,网络安装
  10. python 反传播_反向传播算法详解和Python代码实现
  11. java 日期 英文月份_java日期月份转英文格式
  12. 16进制,BCD码,ASCII转换
  13. C语言如何计算数组的长度
  14. 920记者招待会: 对话详解海尔张瑞敏首席的人单合一
  15. Aspose 只更新页码和 更新域 UpdatePageNumbers
  16. drtek收音机使用说明_车载收音机按键图解说明,老式车载收音机说明书
  17. ABPA 对文件的存取
  18. 新形势下国家医疗保障局信息化建设注意点(三)建设省级平台
  19. VC6.0多线程的问题
  20. 今天的资料里有超实用的Excel图表模板,其中还包含了饼形图、条形图、仪表图、圆环图、折线图、柱形图等12种工作中常用图形~

热门文章

  1. Java8新特性LocalDateTime获取年,月,周,当年第X周
  2. Android面试题(25)-Bundle机制
  3. 2021安徽省高考成绩排名查询,2021年安徽高考成绩排名查询系统,安徽高考位次排名表...
  4. 【安卓学习之常见问题】 Google Play问题-Android 4.4.4平板电脑不能安装 -- (Your device isn‘t compatible with this version)
  5. S32K14x CAN休眠唤醒的实现方案
  6. 【php】分享一个php转换微信、QQ、微博 特殊非主流 | 杀马特 网名的 function
  7. java的面试问题,Java开发者必看
  8. 调试接口用的HTML,javascript调试接口
  9. 适合零基础学习Python的书籍
  10. 企业WiFi覆盖,解决覆盖四大难题