Set
特点:
1、无序,元素的顺序不是按照插入的顺序,也不是根据大小来排序。
2、不重复。插入元素时先比较哈希值,不同则插入,相同再调用equals方法比较,不同则是哈希冲突,可以通过链表法或再哈希法等方法解决,否则插入失败。
主要作用:
1、判断某个元素是否存在
2、判断元素是否重复。将一组数插入集合,比较插入前的元素个数和集合的长度。
leetcode大部分使用的是HashSet,偶尔会用到TreeSet。
HashSet
插入元素时,先通过哈希函数得到哈希值,判断哈希值在哈希表中对应位置是否已经存在元素,不存在则直接插入,存在则调用equals方法比较二者的值,相同则是同一个元素,插入失败;不同则是哈希冲突,可以通过链表法或再哈希法解决。链表法指的是在内存中再找一块地方存储,然后将之前存在的元素的next指针指向这块存储位置。
判断数据结构的好坏要对比四个操作
1、访问Access
set集合没有索引的概念,不存在访问的操作。
2、搜索Search
要搜索一个元素,先通过哈希函数得到哈希值,然后去哈希表上哈希值对应位置看有没有这个元素。
如果没有哈希冲突,则该位置上只有一个元素,时间复杂度是O(1)。
如果有哈希冲突,则该位置上是一条长度为k的链表,时间复杂度是O(k)。
3、插入Insert
要插入一个元素,先通过哈希函数得到哈希值,然后去哈希表上哈希值对应位置看是否已经存在元素。
如果没有哈希冲突,则该位置上没有元素,直接插入,时间复杂度是O(1)。
如果有哈希冲突,则该位置上是一条长度为k的链表,时间复杂度是O(k)。
4、删除Delete
要删除一个元素,先通过哈希函数得到哈希值,然后去哈希表上哈希值对应位置搜索元素。
如果没有哈希冲突,则该位置上只有一个元素,直接删除,时间复杂度是O(1)。
如果有哈希冲突,则该位置上是一条长度为k的链表,时间复杂度是O(k)。
Java哈希表常用操作
1、创建集合
HashSet<Interger>
set = new HashSet<>();
2、添加元素
set.add(10);
set.add(3);
set.add(5);
set.add(2);
set.add(2);
在集合中的顺序可能是10 3 5 2,也可能是其它的顺序,因为set是无序的。
插入两个2,集合中只会存在一个2。
没有哈希冲突的情况下,时间复杂度是O(1)。
3、搜索元素
set.contains(3);
没有哈希冲突的情况下,时间复杂度是O(1)。
4、删除元素
set.remove(3);
没有哈希冲突的情况下,时间复杂度是O(1)。
5、集合长度
int length = set.size();
创建集合时会在内部创建一个变量来记录元素个数,增删会随之改变,调用size()直接返回这个变量。
6、set集合相关leetcode
No.217 存在相同元素
之前使用了哈希表来解决,这里使用哈希集合的不重复特性来解决
思路:将数组中的值加入哈希集合,然后判断数组的长度和哈希集合的长度是否相等,因为哈希集合不允许相同元素的存在,所以如果二者长度相等,则表示没有数组中没有相同元素,否则有相同元素。
class Solution {
public boolean containsDuplicate(int[] nums) {
//使用哈希集合
if(nums == null || nums.length == 0 || nums.length == 1)
return false;
HashSet<Integer> set = new HashSet<>();
for(int num : nums) {
set.add(num);
}
if(nums.length == set.size())
return false;
else
return true;
}
}
No.705 设计哈希集合
思路:因为题目中说明了元素的范围是0到1000000,所以可以创建一个索引是0到1000000的数组布尔类型的数组来实现,布尔类型的初始值均为false,表示该索引位置上没有元素,即哈希集合为空。如果要添加某个元素key,则将数组中的索引key的值改为true,表明该位置上已经存在值,即哈希集合存在元素key。如果删除元素,则将数组中索引key的值改为fasle,表明该位置不存在值,即哈希集合不存在元素key。如果要判断数组中是否存在某个值key,直接将数组索引key的值返回即可。这样添加、删除、搜索的时间复杂度均为O(1),与哈希集合一致。
class MyHashSet {
boolean[] hash = null;
/** Initialize your data structure here. */
public MyHashSet() {
hash = new boolean[1000001];
}
public void add(int key) {
hash[key] = true;
}
public void remove(int key) {
hash[key] = false;
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
return hash[key];
}
}