明天又上java(⊙﹏⊙)...眼前一黑,好怕挂科啊!
1 题目:
/*
给定一个整数数组 nums 和一个整数目标值 target,
请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
*/
2 哈希表思路及算法
注意到方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高。因此,我们需要一种更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出它的索引。
使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N) 降低到 O(1)。
这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
3实现代码
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
作者:力扣官方题解
4 复杂度分析
时间复杂度:O(N),其中 N 是数组中的元素数量。对于每一个元素 x,我们可以 O(1) 地寻找 target - x。
空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。
5 Integer是什么意思?
在 Java 里,Integer
[ˈɪntɪdʒər] 是一个包装类。
其作用是将基本数据类型 int
封装成对象。Java 是一种面向对象的编程语言,不过为了提升性能,它也包含了 int
、double
等基本数据类型。为了能在需要对象的场景中使用这些基本数据类型,Java 为每个基本数据类型都设计了对应的包装类,Integer
就是 int
类型的包装类。
每一个基本数据类型 -------------->有对应的包装类
(为什么需要包装类?)
Integer
类的主要功能
-
基本数据类型与对象之间的转换
- 借助
Integer
类,能够把int
类型的值封装成Integer
对象(装箱,Boxing)。 - 也可以将
Integer
对象转换为int
类型的值(拆箱,Unboxing)。
- 借助
-
处理
int
类型时的工具方法Integer
类提供了一些实用方法,例如将字符串转换为int
类型的parseInt()
方法。- 还有获取
int
类型的最大值和最小值等常量,像Integer.MAX_VALUE
和Integer.MIN_VALUE
。
常见用法示例
java
public class IntegerExample {
public static void main(String[] args) {
// 装箱:将 int 转换为 Integer
int primitiveInt = 42;
Integer wrappedInt = Integer.valueOf(primitiveInt); // 显式装箱
Integer autoWrapped = primitiveInt; // 自动装箱(Java 5 及以后版本支持)
// 拆箱:将 Integer 转换为 int
int unboxedInt = wrappedInt.intValue(); // 显式拆箱
int autoUnboxed = wrappedInt; // 自动拆箱(Java 5 及以后版本支持)
// 字符串转换
String numberStr = "123";
int parsedInt = Integer.parseInt(numberStr); // 字符串转 int
Integer wrappedParsed = Integer.valueOf(numberStr); // 字符串转 Integer
// 常量使用
System.out.println("int 的最大值: " + Integer.MAX_VALUE);
System.out.println("int 的最小值: " + Integer.MIN_VALUE);
}
}
自动装箱与自动拆箱
在 Java 5 及以后的版本中,引入了自动装箱(Autoboxing)和自动拆箱(Auto-unboxing)功能,这使得基本数据类型和包装类之间的转换变得更加简便,无需手动调用 valueOf()
和 intValue()
方法。
Integer
与 int
的区别
- 类型方面:
int
是基本数据类型,而Integer
是引用类型。 - 空值处理方面:
int
不能为null
,但Integer
可以被赋值为null
,所以在需要表示 “无值” 的情况下,使用Integer
会更合适。 - 性能方面:由于
int
是基本数据类型,不涉及对象的创建和垃圾回收,因此在性能上要优于Integer
。所以在对性能要求较高且不需要使用对象特性时,建议使用int
。
典型应用场景
- 在泛型中使用,例如
List<Integer>
不能使用List<int>
。 - 在 JavaBean 中作为属性类型,这样可以利用
null
值来表示属性未被设置。 - 在集合框架中存储整数。
- 在需要调用
Integer
类的静态方法时使用,比如parseInt()
。
理解 Integer
类有助于你在 Java 编程中更好地处理基本数据类型和对象之间的关系,特别是在涉及泛型、集合和空值处理的场景中。
6 那么写成 Map<Integer,Integer>是什么意思?
Map<Integer, Integer>
是 Java 中使用泛型定义的一个映射(Map)接口,它表示这个映射存储的键(Key)和值(Value)都是 Integer
类型。简单来说,这是一个用于存储整数对的容器,其中每个键对应一个唯一的值,且两者都是整数类型。
关键概念解析
-
Map
接口
Map
是 Java 集合框架中的一个接口,用于存储键值对(Key-Value Pairs),特点是:- 键唯一:每个键只能对应一个值,重复的键会覆盖原有值。
- 无序性:默认不保证元素的顺序(如
HashMap
),但可通过LinkedHashMap
或TreeMap
实现有序。
-
泛型参数
<Integer, Integer>
- 键类型:
Integer
(存储整数作为键)。 - 值类型:
Integer
(存储整数作为值)。
例如,键可以是学生的学号(整数),值可以是对应的分数(整数)。
- 键类型:
常见用法示例
java
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// 创建一个键值都是 Integer 的 Map
Map<Integer, Integer> scoreMap = new HashMap<>();
// 添加键值对
scoreMap.put(1001, 95); // 学号 1001 的分数是 95
scoreMap.put(1002, 88);
scoreMap.put(1003, 92);
// 获取值
int score = scoreMap.get(1001); // 返回 95
// 检查键是否存在
boolean hasKey = scoreMap.containsKey(1002); // true
// 遍历 Map
for (Map.Entry<Integer, Integer> entry : scoreMap.entrySet()) {
int key = entry.getKey();
int value = entry.getValue();
System.out.println("学号: " + key + ", 分数: " + value);
}
}
}
常用实现类
-
HashMap
- 无序存储,基于哈希表实现,性能最优(平均时间复杂度
O(1)
)。 - 允许
null
键和null
值(但键只能有一个null
)。
- 无序存储,基于哈希表实现,性能最优(平均时间复杂度
-
TreeMap
- 按键的自然顺序(或自定义比较器)排序,基于红黑树实现。
- 不允许
null
键。
-
LinkedHashMap
- 按插入顺序或访问顺序存储,基于哈希表 + 链表实现。
- 保留插入顺序,性能略低于
HashMap
。
为什么使用 Integer
而不是 int
?
- 泛型限制:Java 泛型要求使用引用类型(如
Integer
),不能直接使用基本类型(如int
)。 - 自动装箱 / 拆箱:Java 会自动转换
int
和Integer
,例如:java
scoreMap.put(1001, 95); // 自动将 int 95 装箱为 Integer int score = scoreMap.get(1001); // 自动将 Integer 拆箱为 int
常见应用场景
- 统计频率:例如统计数组中每个数字出现的次数。
- 缓存数据:用 ID 作为键,缓存对应的数值结果。
- 映射关系:如学生 ID 与成绩、商品 ID 与库存数量等。
注意事项
-
键的唯一性:重复的键会覆盖原有值。
java
scoreMap.put(1001, 95); scoreMap.put(1001, 98); // 键 1001 的值被更新为 98
-
空指针异常:若键不存在,
get(key)
返回null
,拆箱时可能引发NullPointerException
。java
Integer score = scoreMap.get(1004); // 返回 null int s = score; // 报错:NullPointerException
建议使用
getOrDefault(key, defaultValue)
避免空值。
通过 Map<Integer, Integer>
,你可以高效地管理整数键值对,适用于各种需要快速查找和存储数值关系的场景。
7 为什么不写<int,int>?
在 Java 中,泛型(如 Map<Integer, Integer>
)要求使用引用类型(如 Integer
),而不能直接使用基本类型(如 int
)。这是由 Java 泛型的设计原则决定的,主要原因如下:
1. 泛型的类型擦除机制
Java 的泛型是通过类型擦除(Type Erasure)实现的。在编译时,泛型类型参数会被擦除为它们的上限类型(通常是 Object
)。例如:
java
List<Integer> list = new ArrayList<>();
// 编译后等价于:
List list = new ArrayList(); // 泛型信息被擦除,只保留 Object
由于 Object
是所有引用类型的基类,但不是基本类型的基类,因此泛型无法直接使用 int
、double
等基本类型。
2. 基本类型与引用类型的差异
- 基本类型(如
int
、char
):直接存储值,不继承自Object
,没有方法和属性。 - 引用类型(如
Integer
、String
):是类的实例,继承自Object
,可以调用方法(如Integer.parseInt()
)。
泛型设计的初衷是为了提供类型安全的集合操作,而集合框架(如 Map
、List
)只能存储对象。因此,泛型要求使用引用类型。
3. 自动装箱与拆箱的折中方案
为了简化基本类型和引用类型的转换,Java 5 引入了自动装箱 / 拆箱(Autoboxing/Unboxing)机制:
java
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 100); // 自动装箱:int → Integer
int value = map.get(1); // 自动拆箱:Integer → int
虽然底层仍需创建 Integer
对象,但语法上允许直接使用基本类型,掩盖了装箱 / 拆箱的开销。
4. 性能考虑
自动装箱 / 拆箱会带来一定的性能开销(如对象创建和垃圾回收)。在对性能要求极高的场景下,可以使用第三方库(如 Trove、FastUtil)提供的原始类型集合,例如:
java
// Trove 库的原始类型 Map
TIntIntMap map = new TIntIntHashMap();
map.put(1, 100); // 直接存储 int,无需装箱
int value = map.get(1); // 直接返回 int
为什么不能直接支持 <int, int>
?
- 类型系统限制:泛型的类型擦除机制与基本类型不兼容,无法将
int
擦除为Object
。 - 向后兼容性:Java 的泛型是在 JDK 5 引入的,为了兼容已有代码,设计时选择了类型擦除方案,导致无法直接支持基本类型。
- 语法一致性:如果允许
<int, int>
,需要为泛型单独设计两套语法规则(引用类型和基本类型),增加语言复杂度。
总结
- 必须使用引用类型:Java 泛型要求类型参数必须是引用类型,因此
Map<int, int>
会编译错误。 - 自动装箱 / 拆箱:通过
Integer
配合自动装箱 / 拆箱,可以在语法上简化基本类型的使用。 - 性能优化:对性能敏感的场景可使用第三方库的原始类型集合。
例如,正确的写法是:
java
Map<Integer, Integer> map = new HashMap<>(); // ✅ 正确
// Map<int, int> map = new HashMap<>(); ❌ 错误:不支持基本类型
8 java为什么需要包装类?
Java 引入包装类(如 Integer
、Double
、Boolean
等)主要是为了在面向对象的环境中统一处理基本数据类型和对象,解决基本类型无法满足的场景需求。以下是包装类的核心作用及必要性:
1. 泛型系统的强制要求
Java 泛型(如 List<T>
、Map<K,V>
)要求类型参数必须是引用类型,不能直接使用基本类型。包装类是基本类型的对象形式,因此是泛型的唯一选择:
java
// 正确:使用 Integer 包装类
List<Integer> list = new ArrayList<>();
list.add(10); // 自动装箱 int → Integer
// 错误:不能直接使用基本类型
// List<int> list = new ArrayList<>(); ❌
2. 满足面向对象编程的需求
- 统一 API 设计:包装类允许基本类型通过对象形式参与面向对象的操作,例如调用方法、实现接口:
java
Integer num = 10; String binary = num.toBinaryString(); // 调用对象方法 Comparable<Integer> comp = num; // 实现 Comparable 接口
- 集合框架的兼容性:Java 集合(如
ArrayList
、HashMap
)只能存储对象,包装类使基本类型可以存入集合:java
List<Integer> numbers = new ArrayList<>(); numbers.add(42); // 自动装箱为 Integer
3. 支持 null
值表示缺失状态
基本类型(如 int
、boolean
)有默认值(如 0
、false
),无法表示 “无值” 状态。包装类可以赋值为 null
,适用于需要显式表示缺失值的场景:
java
Integer score = null; // 表示分数未设置
if (score != null) {
System.out.println("分数: " + score);
} else {
System.out.println("分数未知");
}
4. 提供实用工具方法
包装类包含静态方法和常量,用于基本类型的转换和操作:
java
// 字符串转整数
int num = Integer.parseInt("123");
// 最大值/最小值常量
System.out.println(Integer.MAX_VALUE); // 2147483647
// 进制转换
String hex = Integer.toHexString(255); // "ff"
5. 反射与序列化的需要
- 反射机制:Java 反射只能操作对象,包装类使基本类型可以通过反射处理:
java
Class<?> intClass = Integer.TYPE; // 获取 int 的 Class 对象
- 序列化:需要将基本类型转换为对象以便在网络或文件中传输:
java
Integer num = 10; ObjectOutputStream oos = new ObjectOutputStream(...); oos.writeObject(num); // 序列化 Integer 对象
6. 自动装箱与拆箱的便利性
Java 5 引入的自动装箱 / 拆箱机制(Autoboxing/Unboxing)掩盖了基本类型和包装类的转换细节,简化了代码:
java
Integer wrapper = 10; // 自动装箱:int → Integer
int primitive = wrapper; // 自动拆箱:Integer → int
但需注意避免空指针异常(NullPointerException
):
java
Integer nullable = null;
int value = nullable; // 报错:NullPointerException
性能权衡
虽然包装类提供了灵活性,但对象创建和垃圾回收会带来性能开销。在性能敏感的场景(如大量数据计算),建议优先使用基本类型:
java
// 基本类型数组(性能优)
int[] arr = new int[1000];
// 包装类集合(性能略低)
List<Integer> list = new ArrayList<>(1000);
总结
Java 的包装类是为了填补基本类型在面向对象系统中的不足:
- 泛型支持:使基本类型能参与泛型操作。
- 对象特性:提供方法调用、
null
值支持等。 - 工具功能:包含类型转换、进制处理等实用方法。
- 系统兼容性:适配反射、序列化等需要对象的场景。
自动装箱 / 拆箱机制平衡了代码简洁性和类型安全,但在性能关键场景需谨慎使用。