3.9哈希+双指针+滑动窗口

This commit is contained in:
zhangsan 2025-03-09 13:08:48 +08:00
parent 4d6b623f9a
commit f3a0b60f0f
11 changed files with 547 additions and 0 deletions

View File

@ -0,0 +1,86 @@
package hash;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* 题目49.字母异位词分组 (groupAnagrams)
* 描述给你一个字符串数组请你将 字母异位词 组合在一起可以按任意顺序返回结果列表
* 字母异位词 是由重新排列源单词的所有字母得到的一个新单词
* 链接https://leetcode.cn/problems/group-anagrams
*
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
*/
//做出来了
public class GroupAnagrams {
//计数
public List<List<String>> groupAnagrams1(String[] strs) {
// 创建一个 Map键是编码后的字符串值是字母异位词列表
HashMap<String, List<String>> map = new HashMap<>();
// 遍历输入数组
for (String str : strs) {
// 统计每个字母出现的次数
int[] count = new int[26];
for (char c : str.toCharArray()) {
count[c - 'a']++; // 统计字母出现次数
}
// 将字母统计结果编码为字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 26; i++) {
sb.append('#'); //必须加 [bdddddddddd, bbbbbbbbbbc] 都是01010... 01010...
sb.append(count[i]);
}
String key = sb.toString();
// 如果 Map 中不存在该键则创建一个新的列表
if (!map.containsKey(key)) {
map.put(key, new ArrayList<>());
}
// 将当前单词添加到对应的列表中
map.get(key).add(str);
}
// 返回 Map 中的所有值即字母异位词列表
return new ArrayList<>(map.values());
}
//排序
public List<List<String>> groupAnagrams(String[] strs) {
// 创建一个 Map键是标准化后的字符串值是字母异位词列表
HashMap<String, List<String>> map = new HashMap<>();
// 遍历输入数组
for (String str : strs) {
// 将单词转换为字符数组并排序
char[] charArray = str.toCharArray();
Arrays.sort(charArray);
String sortedStr = new String(charArray);
// 如果 Map 中不存在该键则创建一个新的列表
if (!map.containsKey(sortedStr)) {
map.put(sortedStr, new ArrayList<>());
}
// 将当前单词添加到对应的列表中
map.get(sortedStr).add(str);
}
// 返回 Map 中的所有值即字母异位词列表
return new ArrayList<>(map.values());
}
}

View File

@ -0,0 +1,55 @@
package hash;
import java.util.HashMap;
import java.util.HashSet;
/**
* 题目128.最长连续序列 (longestConsecutive)
* 描述给定一个未排序的整数数组 nums 找出数字连续的最长序列不要求序列元素在原数组中连续的长度
* 请你设计并实现时间复杂度为 O(n) 的算法解决此问题
* 链接https://leetcode.cn/problems/longest-consecutive-sequence/
*
示例 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
*/
//没做出来
public class LongestConsecutive {
public int longestConsecutive(int[] nums) {
// 将数组中的所有元素存入 HashSet
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int longestStreak = 0;
// 遍历数组中的每个元素
for (int num : set) {
// 如果当前元素是连续序列的起点即没有前驱元素
if (!set.contains(num - 1)) {
int currentNum = num;
int currentStreak = 1;
// 计算以当前元素为起点的连续序列的长度
while (set.contains(currentNum + 1)) {
currentNum++;
currentStreak++;
}
// 更新最长连续序列的长度
longestStreak = Math.max(longestStreak, currentStreak);
}
}
return longestStreak;
}
}

View File

@ -0,0 +1,29 @@
package hash;
import java.util.HashMap;
/**
* 题目1.两数之和 (Two Sum)
* 描述给定一个整数数组 nums 和一个目标值 target请你在该数组中找出和为目标值的那两个整数并返回它们的数组下标
* 链接https://leetcode.cn/problems/two-sum/
*
* 示例 1
*
* 输入nums = [2,7,11,15], target = 9
* 输出[0,1]
* 解释因为 nums[0] + nums[1] == 9 返回 [0, 1]
*/
//做出来了
public class TwoSum {
public int[] twoSum(int[] nums, int target) {
HashMap<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); // 将当前元素和索引存入 map
}
throw new IllegalArgumentException("No two sum solution"); // 如果没有解抛出异常
}
}

View File

@ -0,0 +1,72 @@
package slidingwindow;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* 题目438.找到字符串中所有字母异位词 (findAnagrams)
* 描述给定两个字符串 s p找到 s 中所有 p 异位词 的子串返回这些子串的起始索引不考虑答案输出的顺序
* 链接https://leetcode.cn/problems/find-all-anagrams-in-a-string/
*
示例 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" 的异位词
*/
//没做出来
public class FindAnagrams {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> result = new ArrayList<>();
if (s == null || p == null || s.length() < p.length()) {
return result;
}
int[] pCount = new int[26];
int[] sCount = new int[26];
// 统计 p 中每个字符的频率
for (char c : p.toCharArray()) {
pCount[c - 'a']++;
}
int windowSize = p.length();
// 初始化滑动窗口
for (int i = 0; i < windowSize; i++) {
sCount[s.charAt(i) - 'a']++;
}
// 比较初始窗口
if (Arrays.equals(sCount,pCount)) {
result.add(0);
}
// 滑动窗口
for (int i = windowSize; i < s.length(); i++) {
// 移除窗口左边的字符
sCount[s.charAt(i - windowSize) - 'a']--;
// 添加窗口右边的字符
sCount[s.charAt(i) - 'a']++;
// 比较当前窗口
if (Arrays.equals(sCount,pCount)) {
result.add(i - windowSize + 1);
}
}
return result;
}
}

View File

@ -0,0 +1,47 @@
package slidingwindow;
import java.util.HashMap;
import java.util.HashSet;
/**
* 题目3.无重复字符的最长子串 (lengthOfLongestSubstring)
* 描述给定一个字符串 s 请你找出其中不含有重复字符的 最长 子串 的长度
* 链接https://leetcode.cn/problems/longest-substring-without-repeating-characters/
*
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc"所以其长度为 3
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"所以其长度为 1
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke"所以其长度为 3
请注意你的答案必须是 子串 的长度"pwke" 是一个子序列不是子串
*/
public class LengthOfLongestSubstring {
public int lengthOfLongestSubstring(String s) {
int left=0,right=0,max_length=0;
HashSet<Character> set=new HashSet<>();
while (left<=right && right<s.length()){
char temp=s.charAt(right);
if(!set.contains(temp)){
set.add(temp);
if((right-left+1)>max_length){
max_length=right-left+1;
}
right+=1;
}
else {
set.remove(s.charAt(left));
left+=1;
}
}
return max_length;
}
}

View File

@ -0,0 +1,58 @@
package twopointers;
/**
* 题目11.盛最多水的容器 (maxArea)
* 描述给定一个长度为 n 的整数数组 height n 条垂线 i 条线的两个端点是 (i, 0) (i, height[i])
* 找出其中的两条线使得它们与 x 轴共同构成的容器可以容纳最多的水
* 返回容器可以储存的最大水量
* 说明你不能倾斜容器
* 链接https://leetcode.cn/problems/container-with-most-water/
*
示例 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
*/
public class MaxArea {
//暴力解法O(N^2) 没过所有例子
public int maxArea1(int[] height) {
int maxarea=-1;
int temparea=-1;
for (int i = 0; i < height.length; i++) {
for (int j = i+1; j < height.length; j++) {
temparea=(j-i)*Math.min(height[i],height[j]);
if(temparea>maxarea){
maxarea=temparea;
}
}
}
return maxarea;
}
//双指针
/**
* 在每个状态下无论长板或短板向中间收窄一格都会导致水槽 底边宽度 1 变短
*
* 若向内 移动短板 水槽的短板 min(h[i],h[j]) 可能变大因此下个水槽的面积 可能增大
* 若向内 移动长板 水槽的短板 min(h[i],h[j]) 不变或变小因此下个水槽的面积 一定变小
* 因此初始化双指针分列水槽左右两端循环每轮将短板向内移动一格并更新面积最大值直到两指针相遇时跳出即可获得最大面积
*/
public int maxArea(int[] height) {
int i=0,j=height.length-1;
int maxarea=Integer.MIN_VALUE,temparea=Integer.MIN_VALUE;
while(i<j){
temparea=(j-i)*Math.min(height[i],height[j]);
if(temparea>maxarea){
maxarea=temparea;
}
if (height[i]<height[j])
i+=1;
else
j-=1;
}
return maxarea;
}
}

View File

@ -0,0 +1,46 @@
package twopointers;
/**
* 题目283.移动零 (moveZeroes)
* 描述给定一个数组 nums编写一个函数将所有 0 移动到数组的末尾同时保持非零元素的相对顺序
* 请注意 必须在不复制数组的情况下原地对数组进行操作
* 链接https://leetcode.cn/problems/move-zeroes/
*
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
*/
//做出了但时间复杂度O(N^2)
public class MoveZeroes {
public void moveZeroes1(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if(nums[i]==0){
int temp=-1;
for (int j = i+1; j < nums.length; j++) {
if(nums[j]!=0){
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
break;
}
}
}
}
}
//直接将非0的数字左移即可再填充剩下的格子为0cur左边为已处理完毕的
public void moveZeroes(int[] nums) {
int cur = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
nums[cur] = nums[i];
cur++;
}
}
for (int i = cur; i < nums.length; i++) {
nums[i] = 0;
}
}
}

View File

@ -0,0 +1,64 @@
package twopointers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* 题目15.三数之和 (threeSum)
* 描述给你一个整数数组 nums 判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k j != k 同时还满足 nums[i] + nums[j] + nums[k] == 0 请你返回所有和为 0 且不重复的三元组
* 注意答案中不可以包含重复的三元组
* 链接https://leetcode.cn/problems/3sum/
*
示例 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
*/
//做出来了
public class ThreeSum {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
if(nums[i]>0)break;
if(i>0 && nums[i]==nums[i-1])continue;
int j=i+1;
int k=nums.length-1;
int sum=nums[i]+nums[j]+nums[k];
while(j<k){
if(sum<0)j++;
else if(sum>0)k--;
else {
List<Integer> temp=new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
ans.add(temp);
while(j<k && nums[k-1]==nums[k])k--; //或者用哈希去重
while(j<k && nums[j+1]==nums[j])j++;
k--;
j++;
}
sum=nums[i]+nums[j]+nums[k];
}
}
return ans;
}
}

View File

@ -0,0 +1,37 @@
package hash;
import org.junit.Test;
import twopointers.MoveZeroes;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class HashAlgorithmsTest {
@Test
public void testTwoSum() {
TwoSum solution = new TwoSum();
int[] nums = {2,7,11,15};
int target = 9;
int[] result = solution.twoSum(nums, target);
for (int j : result) {
System.out.println(j);
}
}
@Test
public void testgroupAnagrams(){
GroupAnagrams solution = new GroupAnagrams();
String [] strs = {"bdddddddddd","bbbbbbbbbbc"};
List<List<String>> result=solution.groupAnagrams1(strs);
for (List<String> list : result) {
System.out.println(list);
}
}
@Test
public void testLongestConsecutive() {
LongestConsecutive solution = new LongestConsecutive();
// 测试用例 1
int[] nums1 = {100, 4, 200, 1, 3, 2};
assertEquals(4, solution.longestConsecutive(nums1)); // 预期输出 4
}
}

View File

@ -0,0 +1,22 @@
package slidingwindow;
import org.junit.Test;
import java.util.List;
public class slidingwindowAlgorithmsTest {
@Test
public void testLengthOfLongestSubstring(){
String s = "pwwkew";
LengthOfLongestSubstring solution = new LengthOfLongestSubstring();
int res=solution.lengthOfLongestSubstring(s);
System.out.println(res);
}
@Test
public void testFindAnagrams(){
String s = "cbaebabacd", p = "abc";
FindAnagrams solution = new FindAnagrams();
List<Integer>res=solution.findAnagrams(s,p);
System.out.println(res);
}
}

View File

@ -0,0 +1,31 @@
package twopointers;
import org.junit.Test;
import java.util.List;
public class TwoPointsAlgorithmsTest {
@Test
public void tesrMoveZeroes(){
MoveZeroes solution = new MoveZeroes();
int[] num ={0,1,0,3,12};
solution.moveZeroes(num);
for (int i : num) {
System.out.println(i);
}
}
@Test
public void testMaxArea(){
MaxArea solution = new MaxArea();
int [] height={1,8,6,2,5,4,8,3,7};
int res=solution.maxArea(height);
System.out.println(res);
}
@Test
public void testThreeSum(){
ThreeSum solution = new ThreeSum();
int [] nums={-1,0,1,2,-1,-4};
List<List<Integer>> res = solution.threeSum(nums);
System.out.println(res);
}
}