跳到主要内容力扣热题 100 精选解题思路与代码实现 | 极客日志Javajava算法
力扣热题 100 精选解题思路与代码实现
力扣热题 100 精选解题思路与代码实现涵盖了哈希表、双指针、动态规划、滑动窗口等核心算法思想,提供完整的 Java 代码实现及详细思路解析,适用于技术面试复习与算法能力强化。内容包含经典 LeetCode 题目如两数之和、字母异位词分组、最长连续序列等,并补充了饿了么和淘天的面试真题解析。
链路追踪5 浏览 力扣热题 100 精选解题思路与代码实现
1. 两数之和
- 查找两数之和是否等于 target。
- 找到一个数后,用 target 将其减掉,再寻找应当对应的元素是什么。
- 每找到一个数,就将其放在集合中,因为集合中可以去重,保证只遍历过一次。继续遍历数组,将 target 减去当前的数组中的值,看看已经遍历过的数组中是否有该值,有的话就加入返回结果。
- 没有的话就将其加入。
思想:用集合存放遍历过的数值,然后根据当前定位到的数值,判断自己寻找的数值在集合中是否出现,若出现就返回结果。
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
Map<Integer, Integer> map = new HashMap<>();
if (nums.length == 0 || nums == null) {
return res;
}
for (int i = 0; i < nums.length; i++) {
int temp = target - nums[i];
if (map.containsKey(temp)) {
res[0] = map.get(temp);
res[1] = i;
} else {
map.put(nums[i], i);
}
}
return res;
}
}
2. 字母异位词分组
思想:如果可以重组后构成一个单词,那么可以把字符串先转换成字符数组,然后对字符数组中的字母进行排序。将排序过后的字符数组转换成字符串,然后再作为键出现。然后把键一样的值添加到该键对应的列表当中即可。如果没有该键,那就创建一个新的链表,并同时把键值对插入进去。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = <>();
(String str : strs) {
[] array = str.toCharArray();
Arrays.sort(array);
(array);
List<String> list = map.getOrDefault(key, <>());
list.add(str);
map.put(key, list);
}
<>(map.values());
}
}
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
new
HashMap
for
char
String
key
=
new
String
new
ArrayList
return
new
ArrayList
3. 最长连续序列
思想:遍历该数组,当遍历到的元素在该集合中有前驱的时候就跳过。也就是说,遍历到的数字必须是该序列中第一个打头的才进行处理和操作。并且要记录是当前数字打头的连续序列更长还是已经记录的旧的更长。
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> sets = new HashSet<>();
for (int num : nums) {
sets.add(num);
}
int maxLong = 0;
for (int set : sets) {
int num = set;
if (!sets.contains(num - 1)) {
int curLong = 1;
while (sets.contains(num + 1)) {
num++;
curLong++;
}
maxLong = Math.max(curLong, maxLong);
}
}
return maxLong;
}
}
4. 移动零
思想:使用双指针法进行求解,左指针先不动,指向已经处理好的序列的尾部,右指针寻找不为零的时候,如果不为零,就和 left 指向的元素进行交换。到最后,left 之前的数组就都是不为零的,且位置没有被改变。
class Solution {
public void moveZeroes(int[] nums) {
int left = 0, right = 0, len = nums.length;
while (right < len) {
if (nums[right] != 0) {
int temp = nums[right];
nums[right] = nums[left];
nums[left++] = temp;
}
right++;
}
}
}
5. 面试题精选
饿了么面试真题
- 求 V 字形的数组,也就是连续的三个数字,中间是凹进去的。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] arr = new int[n];
int count = 0;
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
for (int i = 1; i < n - 1; i++) {
if (arr[i] < arr[i - 1] && arr[i] < arr[i + 1]) {
count++;
}
}
System.out.println(count);
}
}
- 第一个数字 n:是字符串的长度,第二个数字 g:是相差应该小于等于的,若数组的位置下标奇偶性相同,且满足相差小于等于 g 那么就是有缘分的位置对数。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int g = scanner.nextInt();
String s = scanner.next();
int[] count1 = new int[26];
int[] count2 = new int[26];
char[] c = s.toCharArray();
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
count1[c[i] - 'a']++;
} else {
count2[c[i] - 'a']++;
}
}
long sum = 0;
for (int i = 0; i < 26; i++) {
sum += (long) count1[i] * (count1[i] - 1) / 2;
for (int j = i + 1; j < 26; j++) {
if (Math.abs(j - i - 1) <= g) {
sum += (long) count1[i] * count1[j];
}
}
}
for (int i = 0; i < 26; i++) {
sum += (long) count2[i] * (count2[i] - 1) / 2;
for (int j = i + 1; j < 26; j++) {
if (Math.abs(j - i - 1) <= g) {
sum += (long) count2[i] * count2[j];
}
}
}
System.out.println(sum);
}
}
淘天面试真题
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[] a = new int[n];
int[][] b = new int[n][m];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
b[i][j] = scanner.nextInt();
}
}
int[] k = new int[m];
List<List<Integer>> ids = new ArrayList<>();
for (int i = 0; i < m; i++) {
k[i] = scanner.nextInt();
ids.add(new ArrayList<>());
for (int j = 0; j < k[i]; j++) {
ids.get(i).add(scanner.nextInt());
}
}
int[] absenceCount = new int[n];
for (int i = 0; i < m; i++) {
for (int studentId : ids.get(i)) {
if (b[studentId - 1][i] == 0 && absenceCount[studentId - 1] <= 10) {
absenceCount[studentId - 1]++;
}
}
}
double[] score = new double[n];
for (int i = 0; i < n; i++) {
score[i] = a[i] * 0.6 + 0.4 * (100 - 10 * absenceCount[i]);
}
double[][] studentScore = new double[n][2];
for (int i = 0; i < n; i++) {
studentScore[i][0] = i + 1;
studentScore[i][1] = score[i];
}
Arrays.sort(studentScore, (x, y) -> {
if (x[1] != y[1]) {
return Double.compare(y[1], x[1]);
} else {
return Double.compare(x[0], y[0]);
}
});
for (double[] s : studentScore) {
System.out.printf("%d %.2f\n", (int) s[0], s[1]);
}
}
}
6. 盛最多水的容器
思想:用双指针法。
注意:记录的结果是从当前计算的结果和上次计算值中选取一个最大的。
class Solution {
public int maxArea(int[] height) {
int l = 0;
int r = height.length - 1;
int result = 0;
while (l < r) {
int area = Math.min(height[l], height[r]) * (r - l);
result = Math.max(result, area);
if (height[l] <= height[r]) {
l++;
} else {
r--;
}
}
return result;
}
}
7. 三数之和
思想:对首个数字去重的时候,考虑的是他在首位出现过了,后面就不用再判断了,因为结果是不含有重复值得。不用再用它打头了。也就是相同位置的相同的数字当前不用再考虑了,因为考虑过了。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
return result;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
if ((nums[i] + nums[left] + nums[right]) < 0) {
left++;
} else if ((nums[i] + nums[left] + nums[right]) > 0) {
right--;
} else {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
}
}
return result;
}
}
8. 最长重复子数组
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
int result = 0;
for (int i = 1; i < nums1.length + 1; i++) {
for (int j = 1; j < nums2.length + 1; j++) {
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
result = Math.max(result, dp[i][j]);
}
}
}
return result;
}
}
9. 最长公共子序列
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[text1.length() + 1][text2.length() + 1];
char[] s1 = text1.toCharArray();
char[] s2 = text2.toCharArray();
for (int i = 1; i < text1.length() + 1; i++) {
char c1 = s1[i - 1];
for (int j = 1; j < text2.length() + 1; j++) {
char c2 = s2[j - 1];
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[text1.length()][text2.length()];
}
}
10. 无重复字符的最长子串
import java.util.HashSet;
import java.util.Set;
class Solution {
public int lengthOfLongestSubstring(String s) {
int result = 0;
int n = s.length();
int l = 0, r = 0;
Set<Character> set = new HashSet<>();
while (r < n) {
if (!set.contains(s.charAt(r))) {
set.add(s.charAt(r));
r++;
result = Math.max(result, r - l);
} else {
set.remove(s.charAt(l));
l++;
}
}
return result;
}
}
11. 找到字符串中所有字母异位词
- 先记录 p 中的每个字母出现了几次,顺带把前 s 的 pn 位也记录了。然后看看前 pn 位中,他们字符出现的次数是否相等。如果相等的话就是字母异位词。
- 然后,开始遍历后续的字符,每后移一个,就把前面的减一个。然后看现在的数量是否一致。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sn = s.length();
int pn = p.length();
int[] s26 = new int[26];
int[] p26 = new int[26];
char[] sc = s.toCharArray();
char[] pc = p.toCharArray();
if (sn < pn) {
return new ArrayList<>();
}
List<Integer> res = new ArrayList<>();
for (int i = 0; i < pn; i++) {
s26[sc[i] - 'a']++;
p26[pc[i] - 'a']++;
}
if (Arrays.equals(s26, p26)) {
res.add(0);
}
for (int i = 0; i < sn - pn; i++) {
--s26[sc[i] - 'a'];
++s26[sc[i + pn] - 'a'];
if (Arrays.equals(s26, p26)) {
res.add(i + 1);
}
}
return res;
}
}
12. 和为 K 的子数组
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
int sum = 0;
for (int j = i; j >= 0; j--) {
sum += nums[j];
if (sum == k) {
count++;
}
}
}
return count;
}
}
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
int count = 0;
int pre = 0;
map.put(0, 1);
for (int i = 0; i < nums.length; i++) {
pre += nums[i];
if (map.containsKey(pre - k)) {
count += map.get(pre - k);
}
map.put(pre, map.getOrDefault(pre, 0) + 1);
}
return count;
}
}
13. 滑动窗口最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
ArrayDeque<Integer> deque = new ArrayDeque<>();
int n = nums.length;
int[] res = new int[n - k + 1];
int id = 0;
for (int i = 0; i < n; i++) {
while (!deque.isEmpty() && deque.peek() < i - k + 1) {
deque.poll();
}
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
deque.offer(i);
if (i >= k - 1) {
res[id++] = nums[deque.peek()];
}
}
return res;
}
}
14. 最大子数组和
class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int sum = Integer.MIN_VALUE;
int count = 0;
for (int i = 0; i < nums.length; i++) {
count += nums[i];
sum = Math.max(sum, count);
if (count < 0) {
count = 0;
}
}
return sum;
}
}
15. 合并区间
class Solution {
public int[][] merge(int[][] intervals) {
int n = intervals.length;
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
int left = intervals[0][0];
int right = intervals[0][1];
for (int i = 1; i < n; i++) {
if (intervals[i][0] > right) {
res.add(new ArrayList<>(Arrays.asList(left, right)));
left = intervals[i][0];
right = intervals[i][1];
} else {
right = Math.max(right, intervals[i][1]);
}
}
res.add(new ArrayList<>(Arrays.asList(left, right)));
int[][] temp = new int[res.size()][2];
for (int i = 0; i < res.size(); i++) {
temp[i][0] = res.get(i).get(0);
temp[i][1] = res.get(i).get(1);
}
return temp;
}
}