引入题目:两数相加

* 给定一个整数数组 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 视图。

实现步骤:

  1. 使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
  2. 遍历Set集合,获取Map集合中的每一个key
  3. 通过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集合)

实现步骤:

  1. 使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
  2. 遍历Set集合,获取每一个Entry对象
  3. 使用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)

使用前提:

当集合中存储的元素的个数已经确定了,不在改变时使用

注意:

  1. of方法只适用于List接口,Set接口,Map接口,不适用于接接口的实现类
  2. of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
  3. Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常

例:

Map<String,Integer> map = Map.of("a",1,"bb",2,"ccc",3);
System.out.println(map);

通过简单的两数相加体会hashmap的好处的更多相关文章

  1. 【LeetCode】两数相加

    题目描述 给出两个非空的链表用来表示两个非负的整数.其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和. ...

  2. LeetCode(2):Add Two Numbers 两数相加

    Medium! 题目描述: 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头 ...

  3. leetcode刷题2:两数相加add_two_numbers

    题目:两数相加 (难度:中等) 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字. 将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以 ...

  4. 两数相加(C#数据结构和算法练习)

    两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表 ...

  5. LeetCoded第2题题解--两数相加

    2.两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表 ...

  6. [CareerCup] 18.1 Add Two Numbers 两数相加

    18.1 Write a function that adds two numbers. You should not use + or any arithmetic operators. 这道题让我 ...

  7. ✡ 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 ...

  8. 简单的两数之和再次乱入<< Add Two Numbers >>

    请看题目描述: You are given two linked lists representing two non-negative numbers. The digits are stored ...

  9. [Swift]LeetCode2. 两数相加 | Add Two Numbers

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

随机推荐

  1. JDBC基础-setFetchSize方法

    在Statement和ResultSet接口中都有setFetchSize方法 void setFetchSize(int rows) throws SQLException 查看API文档 Stat ...

  2. [转] 学习,思维三部曲:WHAT、HOW、WHY(通过现象看本质)

    https://www.douban.com/note/284947308/?type=like 学习技术的三部曲:WHAT HOW WHY 我把学习归类为三个步骤:What.How.Why.经过我对 ...

  3. CentOS 7上修改主机名

                                       如何在CentOS 7上修改主机名                                           在Cent ...

  4. zabbix设置发送消息的时间

    需求:比如我有两个报警的媒介:邮件和微信,但是下班之后,晚上我不希望手机一直响,打扰我睡觉,邮件无所谓,可以24h发送 分析:那现在就需要把微信分时间段发送:比如06:00-24:00   这个时间点 ...

  5. 油猴 tamperMonkey 在百度首页 添加自己的自定义链接

    发现 GM_addStyle 函数不能用了,从写加载css函数. 剩下找个定位 添加内容 就很简单了. // ==UserScript== // @name helloWorld // @namesp ...

  6. DLL动态库多次加载问题

    原因涉及DLL加载和运行机制,主要有两点:1)DLL动态链接库无法独立运行,必须由一个应用程序进程加载到进程空间后才能使用.加载DLL的进程称为宿主进程.被加载的DLL属于宿主进程,不属于宿主进程内某 ...

  7. 微信小程序入口场景的问题整理与相关解决方案

    前言 最近一段时间都在做小程序. 虽然是第二次开发小程序,但是上次做小程序已经是一年前的事了,所以最终还是被坑得死去活来. 这次是从零开始开发一个小程序,其实除了一些莫名其妙的兼容性问题,大多数坑点都 ...

  8. Linux常用命令大全2

    Linux命令是对Linux系统进行管理的命令.对于Linux系统来说,无论是中央处理器.内存.驱动.键盘.鼠标,还是用户等都是文件,Linux命令是它正常运行的核心.接下来,就来看看xp系统下载编辑 ...

  9. 基于HLS(HTTP Live Streaming)的视频直播分析与实现

    转自:http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html HLS(HTTP Live Streaming)的分析: HTT ...

  10. POJ-2442-Sequence(二叉堆)

    POJ-2442 Description Given m sequences, each contains n non-negative integer. Now we may select one ...