LeetCode热题100(一)
1. 两数之和
题目详情
https://leetcode.cn/problems/two-sum/
给定一个整数数组 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]
解答过程
第一时间想到的就是暴力枚举去解决
java
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return null;
}
看了官方的解题思路,十分巧妙的利用map特性,第一次遍历的时候就记录元素及其下标,避免重复遍历
java
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
if (hashMap.containsKey(target - nums[i])) {
return new int[]{hashMap.get(target - nums[i]), i};
}
hashMap.put(nums[i], i);
}
return new int[]{};
}
49. 字母异位词分组
题目详情
https://leetcode.cn/problems/group-anagrams/
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
解释:
- 在 strs 中没有字符串可以通过重新排列来形成
"bat"。 - 字符串
"nat"和"tan"是字母异位词,因为它们可以重新排列以形成彼此。 - 字符串
"ate","eat"和"tea"是字母异位词,因为它们可以重新排列以形成彼此。
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
解答过程
延续上一题的思路,将字符串拆解为字符数组,排序后重新组装为字符串作为key,并记录原始字符
java
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, ArrayList<String>> hashMap = new HashMap<>();
for (String str : strs) {
String s = Arrays.stream(str.split("")).sorted().collect(Collectors.joining());
ArrayList<String> arrayList = hashMap.getOrDefault(s, new ArrayList<>());
arrayList.add(str);
hashMap.put(s, arrayList);
}
return new ArrayList<>(hashMap.values());
}
看了一下官方解题思路基本一致,只是我这里用了切割字符串,然后使用stream处理,确实过于繁琐了
java
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, ArrayList<String>> hashMap = new HashMap<>();
for (String str : strs) {
char[] charArray = str.toCharArray();
Arrays.sort(charArray);
String s = new String(charArray);
ArrayList<String> arrayList = hashMap.getOrDefault(s, new ArrayList<>());
arrayList.add(str);
hashMap.put(s, arrayList);
}
return new ArrayList<>(hashMap.values());
}
另外一种解法利用了"互为字母异位词的两个字符串包含的字母相同",这里不再阐述
128. 最长连续序列
题目详情
https://leetcode.cn/problems/longest-consecutive-sequence/
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
示例 3:
输入:nums = [1,0,1,2]
输出:3
解答过程
延续上一题的思路,第一次的思路是将数组排序后,将连续最大的数字作为key,连续数字开始作为value,记录序列长度,最后通过遍历map去获取长度
java
public int longestConsecutive(int[] nums) {
Arrays.sort(nums);
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int num : nums) {
hashMap.put(num, hashMap.getOrDefault(num - 1, num));
}
int max = 0;
for (Map.Entry<Integer, Integer> entry : hashMap.entrySet()) {
int key = entry.getKey();
int value = entry.getValue();
if (key - value + 1 > max) {
max = key - value + 1;
}
}
return max;
}
后来发现其实可以优化一下,value直接记录长度,但是仍然不是较好的解题思路
java
public int longestConsecutive(int[] nums) {
Arrays.sort(nums);
int max = 0;
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int num : nums) {
int len = hashMap.getOrDefault(num - 1, 0) + 1;
hashMap.put(num, len);
if (len > max) {
max = len;
}
}
return max;
}
官方是使用的hashset处理,看了下评论区其实可以排序后去获取最长序列
java
public int longestConsecutive(int[] nums) {
Integer[] array = Arrays.stream(nums).boxed().distinct().sorted().toArray(Integer[]::new);
int max = 0;
int len = 0;
for (int i = 0; i < array.length; i++) {
if (i == 0) {
len = 1;
} else {
if (array[i] == array[i - 1] + 1) {
len++;
} else {
len = 1;
}
}
if (len > max) {
max = len;
}
}
return max;
}
283. 移动零
题目详情
https://leetcode.cn/problems/move-zeroes/
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
示例 3:
输入:nums = [1,0,1,2]
输出:3
解答过程
这道题是个简单题,但是第一次做的时候还是话费了很长时间,并且不是一次性做对的
- 第一次忽略了没有0的情况,firstZeroIndex初始设置为0导致结果错误
- 第二次忽略了0在元素后的情况,错误交换了顺序
java
public void moveZeroes(int[] nums) {
int firstZeroIndex = -1;
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums.length; j++) {
if (nums[j] == 0) {
firstZeroIndex = j;
break;
}
}
if (nums[i] != 0 && firstZeroIndex != -1 && i > firstZeroIndex) {
nums[firstZeroIndex] = nums[i];
nums[i] = 0;
}
}
// System.out.println(Arrays.toString(nums));
}
11.盛最多水的容器
题目详情
https://leetcode.cn/problems/container-with-most-water/
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
解答过程
直接尝试的暴力解法,但是在数组很长的时候会超时
java
public int maxArea(int[] height) {
int max = -1;
for (int i = 0; i < height.length; i++) {
for (int j = height.length - 1; j >= i + 1; j--) {
int area = Math.min(height[i], height[j]) * (j - i);
if (area > max) {
max = area;
}
}
}
return max;
}
看了解题思路,才写出正确答案,应该使用双指针,由于宽度减少高度不增加的情况下一定会导致面积减小,所以每次移动高度较低的指针
java
public int maxArea(int[] height) {
int max = -1;
int left = 0;
int right = height.length - 1;
System.out.println(left >= right);
while (left < right) {
int area = Math.min(height[left], height[right]) * (right - left);
max = Math.max(max, area);
if (height[left] > height[right]) {
right--;
} else {
left++;
}
System.out.println(max);
}
return max;
}
15. 三数之和
题目详情
https://leetcode.cn/problems/3sum/
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
解答过程
自己没写出来,看了解题思路,根据解题思路实现的,先进行排序,然后遍历第一个元组元素(不允许重复)、遍历第二个元组元素(不允许重复),第三个元组元素从数组末尾往前找,直至指针重合或满足条件,随后检查元组之和是否为0满足则记录元组组合
java
public List<List<Integer>> threeSum(int[] nums) {
ArrayList<List<Integer>> lists = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int k = nums.length - 1;
int target = -nums[i];
for (int j = i + 1; j < nums.length; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
while (j < k) {
System.out.println(nums[i] + " " + nums[j] + " " + nums[k]);
if (nums[j] + nums[k] > target) {
k--;
} else {
break;
}
}
if (j == k) {
break;
}
if (nums[j] + nums[k] == target) {
lists.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[k])));
}
}
}
return lists;
}
42. 接雨水
题目详情
https://leetcode.cn/problems/trapping-rain-water/
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 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
解答过程
自己没写出来,看了很久解题思路才写出来
核心是下雨后水能到达的最大高度等于下标 i 两边的最大高度的最小值,下标 i 处能接的雨水量等于下标 i 处的水能到达的最大高度减去 height[i]
java
public int trap(int[] height) {
int result = 0;
int left = 0;
int right = height.length - 1;
int leftMax = 0;
int rightMax = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
result += leftMax - height[left];
left++;
} else {
result += rightMax - height[right];
right--;
}
}
return result;
}
3. 无重复字符的最长子串
题目详情
https://leetcode.cn/problems/longest-substring-without-repeating-characters/
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。注意 "bca" 和 "cab" 也是正确答案。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解答过程
汗颜 太久没写算法题了 最长字串都不会写了 这里也是看了解题思路写的
这里取了个巧 外层循环每次都clear hashSet方便理解 不需要在外层额外加变量
java
public int lengthOfLongestSubstring(String s) {
int len = 0;
int n = s.length();
HashSet<Character> hashSet = new HashSet<>();
for (int i = 0; i < n; i++) {
hashSet.clear();
int j = i;
while (j < n) {
// System.out.println(i + " " + (j) + " " + hashSet + " " + s.charAt(j) + " " + hashSet.contains(s.charAt(j)));
if (hashSet.contains(s.charAt(j))) {
break;
} else {
hashSet.add(s.charAt(j));
}
j++;
}
len = Math.max(hashSet.size(), len);
}
return len;
}
438. 找到字符串中所有字母异位词
题目详情
https://leetcode.cn/problems/find-all-anagrams-in-a-string/
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
解答过程
看了解题过程后写出来的,首先统计一下目标字符串的字符统计,随后移动窗口,统计窗口内的字符与目标字符串的字符统计进行对比
java
public List<Integer> findAnagrams(String s, String p) {
int sn = s.length();
int pn = p.length();
ArrayList<Integer> arrayList = new ArrayList<>();
if (sn < pn) {
return arrayList;
}
int[] pc = new int[26];
for (int i = 0; i < pn; i++) {
pc[p.charAt(i) - 'a']++;
}
for (int i = 0; i <= sn - pn; i++) {
int[] sc = new int[26];
for (int j = 0; j < pn; j++) {
sc[s.charAt(i + j) - 'a']++;
}
if (Arrays.equals(pc, sc)) {
arrayList.add(i);
}
}
return arrayList;
}
560. 和为 K 的子数组
题目详情
https://leetcode.cn/problems/subarray-sum-equals-k/
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
输入:nums = [1,1,1], k = 2
输出:2
示例 2:
输入:nums = [1,2,3], k = 3
输出:2
解答过程
java
public int subarraySum(int[] nums, int k) {
int c = 0;
for (int i = 0; i < nums.length; i++) {
int result = nums[i];
int j = i + 1;
if (result == k) {
c++;
}
while (j < nums.length) {
result += nums[j];
if (result == k) {
c++;
}
j++;
}
}
return c;
}