哈希
Solution1 两数之和
数组{2, 11, 15, 7},找数组里面和为9的两个数
思路:
①把{2, 11, 15, 7}转为map,map的key就是存储数组中的值,value就是存储数组中对应的索引,得到的map就是<<2,0> , <11,1> , <15,2> ,<7,3>>
②遍历{2, 11, 15, 7},遍历到2时,9-2=7,检查一下7是否在map中,如果map中有7那么说明数组{2, 11, 15, 7}中第0条和第3条数据之和为9
import java.util.HashMap;
import java.util.Map;
public class TwoSum {
public int[] twoSum(int[] nums, int target) {
// 创建一个哈希表来存储数组中的值和对应的索引
Map<Integer, Integer> map = new HashMap<>();
// 遍历数组中的每个元素
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i]; // 计算当前元素需要的配对值
// 检查哈希表中是否包含需要的配对值
if (map.containsKey(complement)) {
// 如果包含,则返回当前元素的索引和配对值的索引
return new int[] {
map.get(complement), i };
}
// 如果不包含,则将当前元素的值和索引存入哈希表
map.put(nums[i], i);
}
// 如果没有找到任何结果,则抛出一个异常(根据题目描述,这种情况不会发生)
throw new IllegalArgumentException("No two sum solution");
}
public static void main(String[] args) {
TwoSum solution = new TwoSum();
int[] nums = {
2, 7, 11, 15};
int target = 9;
int[] result = solution.twoSum(nums, target);
// 输出结果
System.out.println("Indices: [" + result[0] + ", " + result[1] + "]");
}
}
Solution49 字母异位词分组
字母异位词是指由相同字母组成但排列不同的字符串,例如 “eat"和"ate” 就是字母异位词。
解决思路:
①"eat", “tea”, “ate"是字母字母异位词,他们的共同特点是对它们排序后值相等都是"aet”,所以我们用一个Map<String, List>存放结果,map的key就是排序后的内容"aet",value就是[“eat”, “tea”, “ate”]
②遍历字符串数组,对于每个字符串(如"tea"),将其转换为字符数组(如[“t”,“e”,“a”]),然后排序(如[“a”,“e”,“t”]),将排序后的字符数组转换回字符串(如"aet"),作为哈希表的键,往map里面放即可
③如{"eat", "tea", "tan", "ate", "nat", "bat"}
数组对应的map就是
{
"aet":["eat","tea","ate"],
"abt":["abt"],
"ant":["tan","nat"]
}
public class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// key是"eat", "tea", "ate"是字母字母异位词,他们的共同特点是对它们排序后值相等都是"aet"
// map的key就是排序后的内容,value就是["eat", "tea", "ate"]
Map<String, List<String>> map = new HashMap<>();
for (String str : strs) {
// 将字符串转换为字符数组,然后排序
char[] chars = str.toCharArray();
Arrays.sort(chars);
// 将排序后的字符数组转换回字符串,作为哈希表的键
String sortedStr = new String(chars);
// 检查哈希表中是否已包含该键
if (!map.containsKey(sortedStr)) {
// 如果不包含,则创建一个新的列表来存储字母异位词
map.put(sortedStr, new ArrayList<>());
}
// 将当前字符串添加到对应的列表中
map.get(sortedStr).add(str);
}
// 返回哈希表中所有值的列表(即字母异位词组)
return new ArrayList<>(map.values());
}
public static void main(String[] args) {
Solution solution = new Solution();
String[] strs = {
"eat", "tea", "tan", "ate", "nat", "bat"};
List<List<String>> result = solution.groupAnagrams(strs);
// 输出结果
for (List<String> group : result) {
System.out.println(group);
}
}
}
Solution128 最长连续序列
思路:
把数组{1,100, 4, 3, 2, 200}放到set里面去重,然后遍历set里面的每一个值:
- 当前值为1,我看看set里面是否包含2,包含;那我继续看看set里面是否包含3,包含;那我继续看看set里面是否包含4,包含;那我看看set里面是否包含5,不包含;那么当值为1时最长序列为4
- 当前值为100,我看看set里面是否包含101,不包含;那么当值为100时最长序列为1
- 当前值为4,我看看set里面是否包含5,不包含;那么当值为4时最长序列为1
- 当前值为3,我看看set里面是否包含4,包含;那我看看set里面是否包含5,不包含;那么当值为3时最长序列为2
- …
- 其实你看到当值为3时,我看看2是否在set里面,如果2在set里面我就跳过,我就不计算3了,因为从2计算的时候肯定比从3计算出来的最长序列要大
public class Solution {
public int longestConsecutive(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
Set<Integer> numSet = new HashSet<>();
for (int num : nums) {
numSet.add(num);
}
int longestStreak = 0;
for (int num : numSet) {
if (!numSet.contains(num - 1)) {
int currentNum = num;
int currentStreak = 1;
while (numSet.contains(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}
longestStreak = Math.max(longestStreak, currentStreak);
}
}
return longestStreak;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] nums = {
1,100, 4, 3, 2, 200};
System.out.println("Longest consecutive sequence length: " + solution.longestConsecutive(nums)); // Output: 4
}
}
双指针
Solution283 移动零
两个人一起往后走,遇到了一个0,我站在这里不动,你继续往后走;
你往后走的时候遇到了一个非0的数,你把那个数挪过来放到我站的这里,然后我往后走一步,你也继续往后走
思路:
第一次遍历:从index=0开始遍历数组,如果当前元素不是0,则将其放到index指定的位置,并递增index。
第二次遍历:从index开始,将剩余的位置全部填充为0。
public class Solution {
public void moveZeroes(int[] nums) {
int n = nums.length; // 数组的长度
int index = 0; // 用于记录非零元素应该存放的位置
// 遍历数组,将所有非零元素按顺序移动到数组前面
for (int i = 0; i < n; i++) {
if (nums[i] != 0) {
nums[index] = nums[i]; // 将非零元素放到正确的位置
index++; // 更新非零元素应该存放的位置
}
}
// 将剩余的位置填充为0
for (int i = index; i < n; i++) {
nums[i] = 0;
}
}
public static void main(String[] args) {
Solution mz = new Solution();
int[] nums = {
0, 1, 0, 3, 12};
System.out.println("原始数组:");
for (int num : nums) {
System.out.print(num + " ");
}
System.out.println();
mz.moveZeroes(nums);
System.out.println("移动0后的数组:");
for (int num : nums) {
System.out.print(num + " ");
}
}
}
Solution11 盛最多水的容器
思路:
- maxArea用于存储最大水量。
left:指向数组的第一个元素
right:指向数组的最后一个元素 - while (left < right)时循环执行下面逻辑:
计算当前左右指针构成的容器的面积,并更新最大面积。
如果height[left] < height[right],那么left++,否则right–(移动高度较小的指针,因为移动高度较大的指针不会得到更大的面积)
public class Solution {
public int maxArea(int[] height) {
if (height == null || height.length < 2) {
throw new IllegalArgumentException("数组长度必须至少为2");
}
int maxArea = 0;
int left = 0; // 左指针
int right = height.length - 1; // 右指针
while (left < right) {
// 计算当前左右指针构成的容器的面积
int currentArea = Math.min(height[left], height[right]) * (right - left);
// 更新最大面积
maxArea = Math.max(maxArea, currentArea);
// 移动指针的策略:移动高度较小的指针,因为移动高度较大的指针不会得到更大的面积
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return maxArea;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] height = {
1, 8, 6, 2, 5, 4, 8, 3, 7};
int maxWater = solution.maxArea(height);
System.out.println("容器可以储存的最大水量是: " + maxWater);
}
}
Solution15 三数之和
思路:
现在,我们带入数组{-1, 0, 1, 2, -1, -4}
来详细说明处理过程。
-
排序:排序后的数组为:
[-4, -1, -1, 0, 1, 2]
-
遍历数组:我们从索引
0
开始遍历,直到nums.length - 3
,即索引3
。 -
固定元素并寻找双指针
当i = 0时,固定元素为-4,left = 1,right = 5
- 计算和:
-4 + (-1) + 2 = -3
(sum<0,left++
) - 计算和:
-4 + 0 + 2 = -2
(sum < 0
,所以left++
) - 计算和:
-4 + 1 + 2 = -1
(sum < 0
,但此时left
已经等于right - 1
,所以无法再增加left
,结束循环) - 此时
left
和right
相遇,结束循环。
当
i = 1
时,固定元素为-1
,left = 2,right = 5- 计算和:
-1 + (-1) + 2 = 0
(sum=0,加入结果集,结果集:[[-1, -1, 2]]
,left++
,right--
) - 计算和:
-1 + (0) + 1 = 0
(sum=0,加入结果集,结果集:[[-1, -1, 2],[-1,0,1]]
,left++
,right--
) - 此时
left
和right
相遇,结束循环。
当
i = 2
时,固定元素为-1
,由于-1和前面的元素相等,所以结束循环当
i = 3
时,固定元素为0
,left = 4,right = 5- 计算和:
0 + (1) + 2 = 3
(sum>0,right–) - 此时
left
和right
相遇,结束循环。
- 计算和:
public 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 - 2; i++) {
// 跳过重复元素,避免结果中有重复的三元组
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int