通过简单的两数相加体会hashmap的好处
引入题目:两数相加
* 给定一个整数数组 nums 和一个目标值 target
* 请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
* 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
来源:LeetCode
第一种方法:暴力法
通过遍历数组的其余部分来寻找它所对应的目标元素
/**
* 暴力法
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
*
* @param nums
* @param target
* @return
*/
public static int[] twoSum1(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
//因为 nums[0] + nums[1] = 2 + 7 = 9
if ((nums[i] + nums[j]) == target) {
//所以返回 [0, 1]
return new int[]{i, j};
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
第二种方法:两遍哈希表
通过以空间换取速度的方式。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i])是否存在于表中。
/**
* 两遍哈希表
* 时间复杂度:O(n)
* 空间复杂度:O(n)
* @param nums
* @param target
* @return
*/
public static int[] twoSum2(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
//将每个元素的值和索引添加到表中
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
//检查每个元素所对应的目标元素(target - nums[i])是否存在于表中
int complement = target - nums[i];
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[]{i, map.get(complement)};
}
}
throw new IllegalArgumentException("No two sum solution");
}
方法三:一遍哈希表
在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。
/**
* 一遍哈希表
* @param nums
* @param target
* @return
*/
public static int[] twoSum3(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
//如果hashmap里存在对应的目标元素,立即存进结果集合返回
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
通过运行,不难发现,用HashMap的方式速度要快的多。这是因为HashMap集合底层是哈希表,查询的速度特别的快。
JDK1.8之前底层数据结构采用的是:数组+单向链表
JDK1.8之后底层数据结构采用的是:数组+单向链表|红黑树(链表的长度超过8):提高查询的速度
HashMap相关知识:
Map集合
java.util.Map<k,v>集合,是夫妻对儿集合 Map<K,V> ,定义了双列集合规范,每次存储一对儿元素
通过 键 可以找 对应的值 ,K代表键(Key)的类型,V代表值(Value)的类型。
Map集合的特点
- Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
- Map集合中的元素,key和value的数据类型可以相同,也可以不同
- Map集合中的元素,key是唯一的,value是可以重复的
- Map集合中的元素,key和value是一一对应
Map常用子类
HashMap集合、LinkedHashMap集合。
tips:Map接口中的集合都有两个泛型变量,在使用时要为两个泛型变量赋于数据类型。
HashMap集合
java.util.HashMap<k,v>集合 implements Map<k,v>接口
特点:
HashMap集合底层是哈希表:查询的速度特别的快
JDK1.8之前:数组+单向链表

JDK1.8之后:数组+单向链表|红黑树(链表的长度超过8):提高查询的速度

hashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法
LinkedHashMap集合
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
特点:
- LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
- LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的
- 通过哈希表结构可以保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法
Map集合的常用方法
public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
返回值:V
存储键、值对的时候,key不重复,返回值V是null
存储键、值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
public V remove(Object key): 把指定的键 所对应的键、值对元素 在Map集合中删除.
返回被删除元素的值。
key存在,v返回被删除的值 --Integer赋值给int可以自动拆箱
key不存在,v返回null --Integer赋值给int会报错NullPointerException
public V get(Object key): 根据指定的键,在Map集合中获取对应的值。
返回值:
key存在,返回对应的value值
key不存在,返回null
values(): 获取Map中的所有value
Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法:
Set<K> keySet(): 返回此映射中包含的键的 Set 视图。
实现步骤:
- 使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
- 遍历Set集合,获取Map集合中的每一个key
- 通过Map集合中的方法get(key),通过key找到value
例一种最快的:
//使用增强for遍历Set集合
for(String key : map.keySet()){
//通过Map集合中的方法get(key),通过key找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
Map集合遍历的第二种方式:使用Entry对象遍历
Map.Entry<K,V>:在Map接口中有一个Entry接口。作用:存键、值对(结婚证)
Map集合中的方法:
Set<Map.Entry<K,V>> entrySet():获取到Map对象中所有键、值对 对象的集合(Set集合)
实现步骤:
- 使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
- 遍历Set集合,获取每一个Entry对象
- 使用Entry对象中的方法getKey()和getValue()获取键与值
Map集合不能直接使用迭代器或foreach进行遍历。但是转成Set之后就可以用了
HashMap存储自定义类型键值
(可以是对象,也可以是集合/数组)
Map集合保证key是唯一:对象作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
比如:
key:Person类型
Person类就必须重写hashCode方法和equals方法,以保证key唯一
value:String类型
可以重复
又比如:
key:String类型
String类重写hashCode方法和equals方法,可以保证key唯一
value:Person类型
value可以重复(同名同年龄的人视为同一个)
Hashtable<K,V>集合
java.util.Hashtable<K,V>集合 implements Map<K,V>接口
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
Hashtable集合,不能存储null值,null键
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
HashMap集合(之前学的所有的集合):可以存储null值,null键
Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
Hashtable的
子类Properties依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合
静态方法of(E... elements)
JDK9的新特性:
List接口,Set接口,Map接口: 里边增加了一个静态的方法of,可以给集合一次性添加多个元素
static List<E> of(E... elements)
使用前提:
当集合中存储的元素的个数已经确定了,不在改变时使用
注意:
- of方法只适用于List接口,Set接口,Map接口,不适用于接接口的实现类
- of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
- Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
例:
Map<String,Integer> map = Map.of("a",1,"bb",2,"ccc",3);
System.out.println(map);
通过简单的两数相加体会hashmap的好处的更多相关文章
- 【LeetCode】两数相加
题目描述 给出两个非空的链表用来表示两个非负的整数.其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和. ...
- LeetCode(2):Add Two Numbers 两数相加
Medium! 题目描述: 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头 ...
- leetcode刷题2:两数相加add_two_numbers
题目:两数相加 (难度:中等) 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字. 将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以 ...
- 两数相加(C#数据结构和算法练习)
两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表 ...
- LeetCoded第2题题解--两数相加
2.两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表 ...
- [CareerCup] 18.1 Add Two Numbers 两数相加
18.1 Write a function that adds two numbers. You should not use + or any arithmetic operators. 这道题让我 ...
- ✡ leetcode 167. Two Sum II - Input array is sorted 求两数相加等于一个数的位置 --------- java
Given an array of integers that is already sorted in ascending order, find two numbers such that the ...
- 简单的两数之和再次乱入<< Add Two Numbers >>
请看题目描述: You are given two linked lists representing two non-negative numbers. The digits are stored ...
- [Swift]LeetCode2. 两数相加 | Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...
随机推荐
- java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射
java处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的Io类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer. Mapped ...
- Winform用Post方式打开IE
1.主要实现Code void OpenNewIe(string url, string postData)///url是要post的网址,postData是要传入的参数 { if (ie != nu ...
- 1-2 编程基础 GDB程序调试
简介 GDB是GNU发布的一款功能强大的程序调试工具.GDB主要完成下面三个方面的功能: 1.启动被调试程序 2.让被调试的程序在指定的位置停住. 3.当程序被停住时,可以检查程序状态(如变量值). ...
- 一个小笔记(2):Socket网络编程
网络通信的流程: 服务器端申请套接字 -> 绑定套接字到本地,打开端口 -> 监听端口 -> 等待接受消息 -> 有消息之后,读取消息 客户端申请套接字 -> 向服务端发 ...
- 【软件构造】第三章第三节 抽象数据型(ADT)
第三章第三节 抽象数据型(ADT) 3-1节研究了“数据类型”及其特性 ; 3-2节研究了方法和操作的“规约”及其特性:在本节中,我们将数据和操作复合起来,构成ADT,学习ADT的核心特征,以及如何设 ...
- Vickers Vane Pump - Hydraulic Vane Pump Failure: Cavitation, Mechanical Damage
One of our readers recently wrote to me about the following questions: “Recently, we purchased a sec ...
- jQuery判断一个元素是否为另一个元素的子元素(或者其本身)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head& ...
- Git Bash Windows客户端乱码
最近升级Git后,打开Git Bash出现了乱码,解决方法是: 注意,我升级之后,本地和字符集栏位出现了空白的情况.如果检查这里为空白,那么把本地设置为zn_CN,字符集设置为UTF-8
- MySQL丨02丨忘记root用户密码怎么办?
软件:Mysql 版本:8.0.13 1. 先暂停mysql的服务,方法是在cmd里输入如下代码: net stop mysql 2. 在安装文件夹下创建一个文件:mysql-ini.txt (我的安 ...
- 表单中的ngModelController
测试表单中的ngController.直接看红字结论部分即可 <!DOCTYPE html> <html lang="en"> <head> & ...