前两天主要顺着随机开始的第一道链表题目在继续看链表主要还是顾名思义后面想到肯定有优秀的佬对这个热门题单进行了一些整理就开始搜题单分类啥的然后发现力扣里头的学习计划就有里面按照哈希双指针滑动窗口字串等进行了分类于是打算开始补哈希。一.解题记录1.两数之和给定一个整数数组nums和一个整数目标值target请你在该数组中找出和为目标值target的那两个整数并返回它们的数组下标。你可以假设每种输入只会对应一个答案并且你不能使用两次相同的元素。你可以按任意顺序返回答案。以下是一个最直观的穷举时间复杂度还是因n而异的太大了。class Solution { public int[] twoSum(int[] nums, int target) { // 法1最直观的穷举法暴力枚举 // 时间复杂度O(n²)空间复杂度O(1) int lens nums.length; // 获取数组长度 int[] ans new int[2]; // 创建结果数组用于存储找到的两个索引 // 外层循环遍历第一个数从索引0到倒数第二个 for(int i 0; i lens - 1; i) { // 内层循环遍历第二个数从i1到最后一个 // 这样确保不会重复使用同一个元素 for(int j i 1; j lens; j) { // 检查当前两个数的和是否等于目标值 if(nums[i] nums[j] target) { ans[0] i; // 记录第一个数的索引 ans[1] j; // 记录第二个数的索引 return ans; // 找到答案直接返回 } } } // 根据题目说明一定存在一个有效答案 // 但为了语法完整性这里返回ans虽然实际上不会执行到这里 return ans; } }于是开始考虑别的解法此题所属哈希于是去看了下哈希表是啥知识已烟消云散然后看了图解发现有key和value对感觉和字典的感觉很像然后问了下deepseek老师说一个是底层实现一个是外化的概念这样就明白了然后写了第二个方法哈希表法大概的感觉就是有一个key用来记录nums里的数字内容然后value记录目标是否达成01即其余数字中是否存在target-key如果存在就1不存在就0。哈希表就好在他可以直接通过key找所以当前key为2target7那我直接找key5对应的value即可这一步查找时间复杂度比遍历低n降到了1。class Solution { public int[] twoSum(int[] nums, int target) { // 法2哈希表优化法空间换时间 // 时间复杂度O(n)空间复杂度O(n) // 创建哈希表用于存储已经遍历过的数字及其索引 // 键数组中的数字值该数字在数组中的索引 MapInteger, Integer map new HashMap(); // 遍历数组一次循环解决问题 for(int i 0; i nums.length; i) { // 计算当前数字需要的互补数target - 当前数 int complement target - nums[i]; // 检查互补数是否已经在哈希表中 // 如果在说明之前遍历过的某个数 当前数 target if(map.containsKey(complement)) { // 找到答案创建结果数组 int[] ans new int[2]; // 获取互补数在数组中的索引之前存入的 int first map.get(complement); // 第一个数的索引 int second i; // 当前数的索引 // 将两个索引存入结果数组 ans[0] first; ans[1] second; return ans; // 返回结果 } // 如果没找到互补数将当前数字和它的索引存入哈希表 // 供后续数字查找使用 map.put(nums[i], i); } } }49.字母异位词分组给你一个字符串数组请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。示例 1:输入:strs [eat, tea, tan, ate, nat, bat]输出:[[bat],[nat,tan],[ate,eat,tea]]class Solution { public ListListString groupAnagrams(String[] strs) { MapString, ListString map new HashMap(); for (int i 0; i strs.length; i) { char[] chars strs[i].toCharArray(); Arrays.sort(chars); String key new String(chars); ListString list map.get(key); if (list null) { list new ArrayList(); map.put(key, list); } list.add(strs[i]); } return new ArrayList(map.values()); } }时间复杂度O(n * k * log k)空间复杂度O(n * k)其中n 字符串数组strs的长度k 字符串的最大长度二.思考不成熟供参考欢迎指正1前两天写链表时候就有在感受链表这种链式关系和哈希这种线性关系的不同虽然课程都有学到过但当时手懒所以感受并不具体。现在写了几个题的感觉是数组是index-valueindex连续可快速查找信息比如一栋大楼可以快速知道几楼住了谁但不容易知道谁住在几楼而哈希表是key-value不强调key之间的序列关系直接查找key就像是我我直接问xxx住几楼链表则是像是一对一的联络人我和你联络你和它联络当然你也可以链成闭环链在一起bushi。胡言乱语疯狂补习呜呜呜491.引用特性:不需要重复put因为List是引用类型获取List时需要检查是否为null一个指向地址一个指向值拷贝了地址代表改的是同一个东西拷贝值的话是两个东西只是值一样。Java类型分类总表(表格来自deepseek老师如有错误感谢指正)类别类型名称关键字/表示字节数默认值示例代码特点一、基本类型整数类型字节型byte1字节0byte b 127;范围-128~127短整型short2字节0short s 32767;范围-32,768~32,767整型int4字节0int i 21亿;最常用整数类型长整型long8字节0Llong l 100L;范围-2^63~2^63-1浮点类型单精度float4字节0.0ffloat f 3.14f;精度约6-7位小数双精度double8字节0.0ddouble d 3.14;精度约15位小数字符类型字符型char2字节\u0000char c A;Unicode字符布尔类型布尔型boolean未定义falseboolean flag true;只有true/false二、引用类型类类型String类String-nullString s Hello;不可变字符串包装类Integer等-nullInteger i 100;对应8种基本类型自定义类class-nullPerson p new Person();用户定义的类抽象类abstract-nullAnimal a new Dog();不能实例化接口类型内置接口List等-nullListString list new ArrayList();集合框架函数式接口Runnable-nullRunnable r () - {};单一抽象方法自定义接口interface-nullDrawable d () - {};用户定义数组类型一维数组类型[]-nullint[] arr new int[5];长度固定二维数组类型[][]-nullint[][] mat new int[3][3];多维数组对象数组类[]-nullPerson[] ps new Person[10];存储对象枚举类型枚举enum-nullDay d Day.MONDAY;常量集合注解类型注解interface--Override元数据三、特殊类型null类型null--String s null;空引用void类型void--public void method(){}无返回值内存存储对比表(表格来自deepseek老师如有错误感谢指正)特性基本类型引用类型存储位置栈内存栈引用地址 / 堆实际对象变量内容直接存储值存储对象的内存地址赋值操作int b a;→ 复制值List b a;→ 复制引用比较操作比较值比较地址 /equals()比较内容方法传参传值原变量不变传引用可修改对象内容内存大小固定1-8字节不固定引用固定对象可变创建方式直接赋值new关键字或工厂方法性能快栈操作相对慢堆操作垃圾回收2.学习下如何遍历Map方法1for (Map.EntryString, ListString entry : map.entrySet()) { System.out.println(key: \ entry.getKey() \ - entry.getValue()); }Map.Entry: Map接口的内部接口代表一个键值对key-value pairString, ListString: 泛型参数第一个String键的类型第二个ListString值的类型字符串列表作用声明entry变量能存储什么类型的数据读作in在...中【变量此处为键值对entry遍历的一堆变量】map对象 (HashMap) ├── 键值对1 │ ├── key: aet (String对象) │ └── value: [eat,tea,ate] (ArrayList对象) ├── 键值对2 │ ├── key: ant (String对象) │ └── value: [tan,nat] (ArrayList对象) └── 键值对3 ├── key: abt (String对象) └── value: [bat] (ArrayList对象) map.entrySet()返回 Set集合 [ entry1 (Map.Entry对象): 包含对键值对1的引用, entry2 (Map.Entry对象): 包含对键值对2的引用, entry3 (Map.Entry对象): 包含对键值对3的引用 ] for循环遍历这个Set 第一次循环: entry entry1 → entry.getKey()aet → entry.getValue()[eat,tea,ate] 第二次循环: entry entry2 → entry.getKey()ant → entry.getValue()[tan,nat] 第三次循环: entry entry3 → entry.getKey()abt → entry.getValue()[bat]方法2普通for循环 迭代器IteratorMap.EntryString, ListString iterator map.entrySet().iterator(); while (iterator.hasNext()) { Map.EntryString, ListString entry iterator.next(); System.out.println(key: \ entry.getKey() \ - entry.getValue()); }方法3分开获取键和值for (String key : map.keySet()) { ListString value map.get(key); System.out.println(key: \ key \ - value); }方法4Lambda表达式Java 8map.forEach((key, value) - System.out.println(key: \ key \ - value) );内存示意图栈内存 堆内存 map ────────────────→ HashMap对象 ├── table数组 │ ├── [0] → Node对象1 │ │ ├── key ──→ aet (String对象) │ │ └── value ─→ List对象 [eat,tea,ate] │ ├── [1] → Node对象2 │ │ ├── key ──→ ant (String对象) │ │ └── value ─→ List对象 [tan,nat] │ └── [2] → Node对象3 │ ├── key ──→ abt (String对象) │ └── value ─→ List对象 [bat] │ entrySet() ───────────→ Set视图 ├── 包含对Node1的引用 ├── 包含对Node2的引用 └── 包含对Node3的引用 for循环中的entry变量 第一次: entry ──→ Node1的引用 第二次: entry ──→ Node2的引用 第三次: entry ──→ Node3的引用为什么使用entrySet()而不是直接遍历keySet()方式代码性能说明entrySet()entry.getKey()和entry.getValue()高一次遍历获取键值keySet()key和map.get(key)低每次get()都要查询3.char[]和String的互转及楼下char[] chars strs[i].toCharArray();Arrays.sort(chars);String key new String(chars);致谢/参考资料尊敬的力扣老师和尊敬的Deepseek老师声明本文内容仅用于个人学习记录不用于任何商业用途。部分代码、技术观点或示例可能来源于网络或其他公开资源如有侵权请联系我删除。