HashSet是通过HasMap来实现的,HashMap的输入参数有Key、Value两个组成,在实现HashSet的时候,保持HashMap的Value为常量,相当于在HashMap中只对Key对象进行处理。
HashMap的底层是一个数组结构,数组中的每一项对应了一个链表,这种结构称“链表散列”的数据结构,即数组和链表的结合体;也叫散列表、哈希表。
put在放入数据时,如果放入数据的key已经存在与Map中,最后放入的数据会覆盖之前存在的数据,
而putIfAbsent在放入数据时,如果存在重复的key,那么putIfAbsent不会放入值。
128. 最长连续序列
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
题解:
1)sort 比较
2)hashset
3)动态规划
sloution:
1)
class Solution {
public int longestConsecutive(int[] nums) {
if(nums.length < 1) return 0;
if(nums.length == 1) return 1;
Arrays.sort(nums);
int count = 1;
int result = 1;
for(int i = 1; i < nums.length; i++){
if(nums[i] - nums[i-1] == 1){
result++;
}
else if(nums[i] - nums[i-1] == 0) continue;
else{
result = 1;
}
count = Math.max(result,count);
}
return count;
}
}
class Solution {
public int longestConsecutive(int[] nums) {
// 将 nums 使用hash表存储
Set<Integer> num_set = new HashSet();
for (int num : nums) {
num_set.add(num);
}
// 最终的连续元素个数
int longestStreak = 0;
// 迭代hash表中的元素, 若表中不存在 num-1的数, 便开始向后查找与当前元素连续的数
// 此目的是为了避免多次遍历一组连续的数
for (int num : num_set) {
if (!num_set.contains(num - 1)) {
int currentNum = num; // 当前数
int currentStreak = 1; // 连续数个数计数器
// 若存在连续的数,则计数器+1
while (num_set.contains(++currentNum) && (++currentStreak >0));
longestStreak = Math.max(longestStreak, currentStreak);
}
}
return longestStreak;
}
}
从0到nums.length遍历每个元素。
对于每个元素nums[i]我们都dfs的搜索nums中比它小1的元素,每搜索到一个,len+1。直到所有不到下一个为止,保存当前最大len为候选答案。
class Solution {
Set<Integer> checkInNums = new HashSet<>();
//初始化Set用来判断数字是否在nums中
public int longestConsecutive(int[] nums) {
if(nums.length == 0)
return 0;
for(int i = 0; i < nums.length; i++)
checkInNums.add(nums[i]);
int res = 0;
for(int i = 0; i < nums.length; i++)
res = Math.max(res, dfs(nums[i]));
return res;
}
//返回小于等于当前数的最大连续序列的长度
public int dfs(int cur) {
int len = 1; //当前长度为1
if(checkInNums.contains(cur-1))
len += dfs(cur-1);
return len;
}
}
我们很容易发现,dfs形成的递归树中有重复子结构。
比如[100, 4, 200, 1, 3, 2]
我们遍历4时,已经将dfs(3),dfs(2),dfs(1)的情况给遍历过了,因此,再往后递归的时候,我们应该剪枝。
于是添加备忘录Map。
class Solution {
Set<Integer> checkInNums = new HashSet<>(); //初始化Set用来判断数字是否在nums中
Map<Integer, Integer> m = new HashMap<>(); //备忘录
public int longestConsecutive(int[] nums) {
if(nums.length == 0)
return 0;
for(int i = 0; i < nums.length; i++)
checkInNums.add(nums[i]);
int res = 0;
for(int i = 0; i < nums.length; i++)
res = Math.max(res, dfs(nums[i]));
return res;
}
//返回小于等于当前数的最大连续序列的长度
public int dfs(int cur) {
if(m.containsKey(cur))
return m.get(cur);
int len = 1; //当前长度为1
if(checkInNums.contains(cur-1))
len += dfs(cur-1);
m.put(cur, len);
return len;
}
}
作者:robinzhu-z
532. 数组中的K-diff数对
给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对。这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字,且两数之差的绝对值是 k.
示例 1:
输入: [3, 1, 4, 1, 5], k = 2
输出: 2
解释: 数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。
尽管数组中有两个1,但我们只应返回不同的数对的数量。
示例 2:
输入:[1, 2, 3, 4, 5], k = 1
输出: 4
解释: 数组中有四个 1-diff 数对, (1, 2), (2, 3), (3, 4) 和 (4, 5)。
示例 3:
输入: [1, 3, 1, 5, 4], k = 0
输出: 1
解释: 数组中只有一个 0-diff 数对,(1, 1)。
class Solution {
public int findPairs(int[] nums, int k) {
HashSet<Object> set = new HashSet<>();
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i+1; j < nums.length ; j++) {
if (Math.abs(nums[i] - nums[j])==k){
set.add(nums[i] + nums[j]);
}
}
}
return set.size();
}
}
205. 同构字符串(类290)
给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
示例 1:
输入: s = “egg”, t = “add”
输出: true
示例 2:
输入: s = “foo”, t = “bar”
输出: false
示例 3:
输入: s = “paper”, t = “title”
输出: true
题解:
sloution:
class Solution {
public boolean isIsomorphic(String s, String t) {
if(s==null||t==null) return false;
if(s.length()!=t.length()) return false;
HashMap<Character,Character> map=new HashMap<>();
for(int i=0;i<s.length();i++){
//key不存在
if(!map.containsKey(s.charAt(i))){
//value对应就false
if(map.containsValue(t.charAt(i))){
return false;
}
//存入
map.put(s.charAt(i),t.charAt(i));
}else{
//key存在但不对应(一个key两个value的情况)
if(map.get(s.charAt(i))!=t.charAt(i)){
return false;
}
}
}
return true;
}
}
290. 单词规律
给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
示例1:
输入: pattern = “abba”, str = “dog cat cat dog”
输出: true
示例 2:
输入:pattern = “abba”, str = “dog cat cat fish”
输出: false
示例 3:
输入: pattern = “aaaa”, str = “dog cat cat dog”
输出: false
示例 4:
输入: pattern = “abba”, str = “dog dog dog dog”
输出: false
Java split() 分割字符串,返回一个字符串数组。
Java charAt() 返回指定索引处的字符。索引范围为从 0 到 length() - 1。
Java equals() 方法用于将字符串与指定的对象比较。
public boolean equals(Object anObject)
class Solution {
public boolean wordPattern(String pattern, String str) {
if(pattern==null||str==null) return false;
String[] s =str.split(" ");
if(pattern.length()!=s.length) return false;
HashMap<Character,String> map= new HashMap<>();
for(int i=0;i<pattern.length();i++){
char key=pattern.charAt(i);
if(map.containsKey(key)){//containsValve
if(!map.get(key).equals(s[i])) return false;
}
else{
if(map.containsValue(s[i])) return false;
else map.put(key,s[i]);
}
}
return true;
}
}
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
题解:
1)暴力
2)快慢指针 最优
3)hash/set :判断happu number重要的一点是,当出现循环节时,也就是平方和等于前面出现过的数字时ok,所以用哈希表来存储之前算过的数,每次计算后先判断是不是1,如果不是再判断一下之前是否出现过这个数。
sloution:
2)见双指针
3)set
class Solution {
private int calcu(int n){
int sum = 0;
while (n != 0){
sum += n % 10 * (n % 10);
n /= 10;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer> set=new HashSet<>();
set.add(n);
while(true){
n = calcu(n);
if(n == 1)
return true;
if(set.contains(n))
return false;
set.add(n);
}
}
}
287. 寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
不能更改原数组(假设数组是只读的);
只能使用额外的 O(1) 的空间。
题解:
1)hashset 判重 不满2
2)排序 相邻判重 不满1
3)二分查找
4)快慢指针
3、4非常规 见于题解
sloution:
1)set
3、4)见双指针集
class Solution {
public int findDuplicate(int[] nums) {
Set<Integer> set =new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if(!set.add(nums[i])) return nums[i];
}
return -1;
}
}
217. 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
题解:
1)利用set性质
2)一遍哈希遍历
3)排序后判断相邻元素是否相同
sloution:
1)
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> res = new HashSet<Integer>();
for(int i:nums) res.add(i);
return res.size()< nums.length;
}
}
2)
class Solution {
public boolean containsDuplicate(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
int length = nums.length;
for (int i = 0; i < length; i++){
if (map.containsKey(nums[i])){
return true;
}
map.put(nums[i], i);
}
return false;
}
}
作者:lxiaocode
3)
class Solution {
public boolean containsDuplicate(int[] nums) {
int n=nums.length;
Arrays.sort(nums);//排序复杂度O(nlogn)
for(int i=0;i<n-1;i++){
if(nums[i]==nums[i+1])
return true;
}
return false;
}
}
作者:agasar
349. 两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
题解:
1)利用HashSet的性质:无序、元素不重复。先对一组数组排除重复元素,再利用Set contains方法与另一组进行比较
sloution:
1)两set
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> set1=new HashSet<Integer>();
HashSet<Integer> set2=new HashSet<Integer>();
for(int i:nums1) set1.add(i);
for(int i:nums2){
if(set1.contains(i)){
set2.add(i);
}
}
int []new_num = new int[set2.size()];
int j = 0;
for(int i:set2){
new_num[j] = i;
j++;
}
return new_num;
}
}
Java 集合类中的 Set.contains()方法
判断 Set 集合是否包含指定的对象。
该方法返回值为 boolean 类型,如果 Set 集合包含指定的对象,则返回 true,否则返回 false。foreach的语句格式:
for(元素类型t 元素变量x : 遍历对象obj){
引用了x的java语句; }