题目
和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。
数组的子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。
示例 1:
输入:nums = [1,3,2,2,5,2,3,7] 输出:5 解释:最长的和谐子序列是 [3,2,2,2,3]
示例 2:
输入:nums = [1,2,3,4] 输出:2
示例 3:
输入:nums = [1,1,1,1] 输出:0
题目来源:力扣(LeetCode)594
链接:https://leetcode-cn.com/problems/longest-harmonious-subsequence
官方解法
方法一:枚举
我们可以枚举数组中的每一个元素,对于当前枚举的元素 x,它可以和 x + 1 组成和谐子序列。我们再遍历一遍整个数组,找出等于 x 或 x + 1 的元素个数,就可以得到以 x 为最小值的和谐子序列的长度。
复杂度分析:
时间复杂度:O(N^2),其中 N 是数组的长度。
空间复杂度:O(1)。
方法二:哈希映射
在方法一中,我们枚举了 x 后,遍历数组找出所有的 x 和 x + 1。我们也可以用一个哈希映射(HashMap)来存储每个数出现的次数,这样就能在 O(1)O(1) 的时间内得到 x 和 x + 1 出现的次数。
我们首先遍历一遍数组,得到哈希映射。随后遍历哈希映射,设当前遍历到的键值对为 (x, value),那么我们就查询 x + 1 在哈希映射中对应的值,就得到了 x 和 x + 1 出现的次数。
复杂度分析:
时间复杂度:O(N),其中 N 是数组的长度。
空间复杂度:O(N),用来存储哈希映射。
方法三:哈希映射 + 单次扫描
在方法二中,我们需要对数组进行一次扫描,再对哈希映射进行一次扫描。事实上,我们也可以设计出只进行一次扫描的算法。
我们扫描一次数组,当扫描到元素 x 时,我们首先将 x 加入哈希映射,随后获取哈希映射中 x - 1, x, x + 1 三者出现的次数 u, v, w,那么 u + v 即为 x - 1, x 组成的和谐子序列的长度,v + w 即为 x, x + 1 组成的和谐子序列的长度。假设数组中最长的和谐子序列的最后一个元素在数组中的位置为 i,那么在扫描到 nums[i] 时,u + v 和 v + w 中一定有一个就是答案。因此这种方法可以找到最长的和谐子序列的长度。
哈希映射
详细解释(英文版本):
https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
创建HashMap变量
创建HashMap变量需指定键和值的数据类型,格式如下。
HashMap<Integer, String> map = new HashMap<>();
HashMap的put方法——添加值
通过HashMap的put方法可以向变量中添加值。put方法有两个参数,就是要添加的数据的键和值。
map.put(num, map.getOrDefault(num, 0) + 1);
HashMap的get方法——取值
通过HashMap的get方法可以向变量中取值。get方法需要传入一个参数,那个参数是键值,在HashMap中,键值是唯一的。
res = Math.max(res, map.get(key) + map.get(key + 1));
HashMap的keySet()方法——遍历HashMap变量
遍历HashMap变量不能像遍历数组那样直接通过索引值来遍历,可以通过HashMap的keySet()方法获取变量中存放的所有键值,然后再通过遍历键获取对应的值
修改——将原有的值覆盖
在HashMap中,想修改其中存放的值,可以通过使用put方法,将原有的值覆盖。
HashMap的remove方法——删除HashMap变量
由于键值是对应的,所以只有删除HashMap中的键,就会连同删除键对应的值。通过使用HashMap的remove方法,可以删除HashMap变量中的内容。这里讲一下remove方法的两个重载函数,remove(Object key) 和 remove(Object key, Object value)。 这两个函数的区别在于,remove(Object key)直接删除对应的键,而remove(Object key, Object value)需要键和值都对应时才会删除HashMap变量中的内容。
public static void HashMap(){
//创建hashmap变量
HashMap<Integer, String> map = new HashMap<>();
String[] names={"老大","老二","老三","老四"};
for (int i=0;i< names.length;i++){
//向hashmap变量添加值
map.put((i+1),names[i]);
}
System.out.println(map);
//从HashMap变量获取值
String namehashmap=map.get(4);
System.out.println("从HashMap变量获取值:"+namehashmap);
//遍历HashMap变量
/* 遍历HashMap变量不能像遍历数组那样直接通过索引值来遍历,
可以通过HashMap的keySet()方法获取变量中存放的所有键值,然后再通过遍历键获取对应的值 */
System.out.print("遍历HashMap变量:");
for (Integer id:map.keySet()){
System.out.print(" id="+id+" name:"+map.get(id));
}
//修改HashMap变量
//在HashMap中,想修改其中存放的值,可以通过使用put方法,将原有的值覆盖。
System.out.println();
System.out.print("修改HashMap变量:");
System.out.print("修改前:"+map.get(4));//4-老四
map.put(4,"老五");
System.out.print("修改后:"+map.get(4));//4-老四
//删除HashMap变量中的值
/*
由于键值是对应的,所以只有删除HashMap中的键,就会连同删除键对应的值。
通过使用HashMap的remove方法,可以删除HashMap变量中的内容。
这里讲一下remove方法的两个重载函数,
remove(Object key) 和 remove(Object key, Object value)。
这两个函数的区别在于,remove(Object key)直接删除对应的键,
而remove(Object key, Object value)需要键和值都对应时才会删除HashMap变量中的内容。
*/
System.out.println();
System.out.println("删除HashMap变量:");
System.out.println("删除前HashMap变量:");
for (Integer id:map.keySet()){
System.out.print(" id="+id+" name:"+map.get(id));
}
map.remove(2);
System.out.println();
System.out.println("删除后HashMap变量:");
for (Integer id:map.keySet()){
System.out.print(" id="+id+" name:"+map.get(id));
}
}
增强for循环
public static void formedthod(){
int[] arr= {1,2,3,4};
System.out.println();
for (int num:arr){
System.out.print(num+" ");
}
}
官方解释比较详细有PPT分析,建议如果没看懂移步官方题解,本文档仅供理解补充!
本博客是平时学习笔记没有很多技术含量,小白可以来学习一下,也欢迎各位大佬指点!