594 Longest Harmonious Subsequence
We define a harmonious array as an array where the difference between its maximum value and its minimum value is exactly 1
.
Given an integer array nums
, return the length of its longest harmonious subsequence among all its possible subsequences.
A subsequence of array is a sequence that can be derived from the array by deleting some or no elements without changing the order of the remaining elements.
Example 1:
Input: nums = [1,3,2,2,5,2,3,7]
Output: 5
Explanation: The longest harmonious subsequence is [3,2,2,2,3].
Example 2:
Input: nums = [1,2,3,4]
Output: 2
Example 3:
Input: nums = [1,1,1,1]
Output: 0
Constraints:
1 <= nums.length <= 2 * 104
-109 <= nums[i] <= 109
这题很精彩,逐步推进优化,很值得研究。
解法一:brute force,把所有的subsequence找出来,每个check一下是不是LHS。T:O(2^n), S:O(1)。用找二进制的方法挑数,栗子:

具体实现参透了半天,首先把1左移到n的长度,这就是2^n个我们要生成比对的subsequence数目。然后在每个subsequnce,我们挑数,i中位置为1的,我们就在nums里找那个数出来。譬如,i = 2,010,j 从0到2找,j一直向左移,移到等于i有一的地方就会算一遍。
public int findLHS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int res = 0;
for (int i = 0; i < (1 << nums.length); i++) {
int count = 0;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int j = 0; j < nums.length; j++) {
if ((i & (1 << j)) != 0) {
int cur = nums[j];
max = Math.max(max, cur);
min = Math.min(min, cur);
count++;
}
}
if (max - min == 1) {
res = Math.max(res, count);
}
}
return res;
}
解法二:还是很brute force的,但是,这个只用T:O(n^2)和S:O(1)。这里,我们先定了这个sequence一定要包含某数nums[i]。然后,我们从头扫到尾,找等于这个数或者比这个数大1的数。然后每次更新result。因为一定要diff by 1,所以要多加一个flag来记录有没有找到过diff by 1.
public int findLHS(int[] nums) {
if (nums == null || nums.length == 0) {
return Integer.MIN_VALUE;
}
int longest = 0;
for (int i = 0; i < nums.length; i++) {
boolean flag = false;
int count = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[i] == nums[j]) {
count++;
} else if (nums[i] == nums[j] + 1) {
count++;
flag = true;
}
}
if (flag) {
longest = Math.max(longest, count);
}
}
return longest;
}
解法三:排序再找。我们用count和pre_count来记录,每次我们找到同样的,就算到pre_count里。因为max和min一定要diff by one,所以不能直接加起来就算。当我们看到nums[i] - nums[i - 1] == 1的时候,才真正把结果加到count里。找到比现在数字大的数时,记得继续找。找到头了,才算result。还得记得把这个count赋值给pre_count。因为可能下一个数比这个多一,我们要循环继续算。T:O(nlogn)
public int findLHS(int[] nums) {
if (nums == null || nums.length == 0) {
return Integer.MIN_VALUE;
}
Arrays.sort(nums);
int res = 0;
int pre_count = 1;
for (int i = 0; i < nums.length; i++) {
// 一开始要把自己算上,所以是1
int count = 1;
if (i > 0 && nums[i] - nums[i - 1] == 1) {
while (i < nums.length - 1 && nums[i] == nums[i + 1]) {
count++;
i++;
}
res = Math.max(res, count + pre_count);
pre_count = count;
} else {
while (i < nums.length - 1 && nums[i] == nums[i + 1]) {
count++;
i++;
}
pre_count = count;
}
}
return res;
}
解法四:用hashmap来数数。首先用hashmap把每个数字出现得频率数一数。然后再loop一次数组,每次找有多少个与这个数key相同或等于key + 1的数。T:O(n), S:O(n)。
public int findLHS(int[] nums) {
if (nums == null || nums.length == 0) {
return Integer.MIN_VALUE;
}
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
int res = 0;
for (int i = 0; i < nums.length; i++) {
int count = map.get(nums[i]);
if (map.getOrDefault(nums[i] + 1, 0) > 0) {
res = Math.max(count + map.get(nums[i] + 1), res);
}
}
return res;
}
// 参考答案
public int findLHS(int[] nums) {
HashMap < Integer, Integer > map = new HashMap < > ();
int res = 0;
for (int num: nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
for (int key: map.keySet()) {
if (map.containsKey(key + 1))
res = Math.max(res, map.get(key) + map.get(key + 1));
}
return res;
}
解法五:其实还是用hashmap复杂度跟上面一样,就是一圈解决,不用扫两次。如果想一圈解决,就得同时考虑key + 1和key -1的情况。结果是max(res,count + keyPlusOne, count + keyMinusOne)
public int findLHS(int[] nums) {
if (nums == null || nums.length == 0) {
return Integer.MIN_VALUE;
}
Map<Integer, Integer> map = new HashMap<>();
int res = 0;
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
int keyPlusOne = map.getOrDefault(num + 1, 0);
int keyMinusOne = map.getOrDefault(num - 1, 0);
if (keyPlusOne != 0) {
res = Math.max(Math.max(res, keyPlusOne + map.get(num)), keyMinusOne + map.get(num));
}
if (keyMinusOne != 0) {
res = Math.max(Math.max(res, keyPlusOne + map.get(num)), keyMinusOne + map.get(num));
}
}
return res;
}
// 参考答案
public int findLHS(int[] nums) {
HashMap < Integer, Integer > map = new HashMap < > ();
int res = 0;
for (int num: nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
if (map.containsKey(num + 1))
res = Math.max(res, map.get(num) + map.get(num + 1));
if (map.containsKey(num - 1))
res = Math.max(res, map.get(num) + map.get(num - 1));
}
return res;
}
Last updated
Was this helpful?