Longest Harmonious Subsequence

(#594), Easy

Category: Array, Hash Table, Sliding Window, Sorting, Two Pointer

Problem Statement

We define a harmonious array as one where the difference between the maximum and minimum element is exactly 1. Given an array `nums`, return the length of the longest harmonious subsequence you can find. A subsequence can be formed by deleting some or no elements without changing the order of the remaining elements.

Examples

Input: nums = [1, 3, 2, 2, 5, 2, 3, 7]

Output: 5

Explanation: The subsequence [2, 2, 2, 3, 3] is the longest harmonious subsequence.

Input: nums = [1, 2, 3, 4]

Output: 2

Explanation: Both [1, 2] and [2, 3] are valid, so the max is 2.

Input: nums = [1, 1, 1, 1]

Output: 0

Explanation: No other number to pair with 1, so output is 0.

Approach

Sliding Window (Brute Force)

  • Sort the array in ascending order.
  • Initialize two pointers: `start = 0` and `end = 0`.
  • Iterate through the array with `end` pointer.
  • While the difference between `nums[end]` and `nums[start]` is greater than 1, move `start` forward.
  • If the difference is exactly 1, calculate the window length as `end - start + 1` and update the maximum length found so far.
  • Return the maximum length after the loop ends.
var findLHS = function(nums) {
  nums.sort((a, b) => a - b);
  let start = 0, maxLen = 0;
  for (let end = 0; end < nums.length; end++) {
    while (nums[end] - nums[start] > 1) {
      start++;
    }
    if (nums[end] - nums[start] === 1) {
      maxLen = Math.max(maxLen, end - start + 1);
    }
  }
  return maxLen;
};

Optimized (Using Hash Map)

  • Create a HashMap to count the frequency of each element in the array.
  • Loop through each key in the HashMap.
  • For each key, check if `key + 1` exists in the HashMap.
  • If yes, add the counts of `key` and `key + 1`, and update the maximum length.
  • Return the maximum length found.
var findLHS = function(nums) {
  const map = new Map();
  for (let num of nums) {
    map.set(num, (map.get(num) || 0) + 1);
  }
  let maxLen = 0;
  for (let [num, count] of map.entries()) {
    if (map.has(num + 1)) {
      maxLen = Math.max(maxLen, count + map.get(num + 1));
    }
  }
  return maxLen;
};

Complexity

Time: Brute Force: O(n log n) due to sorting. Optimized: O(n) using hash map.

Space: Brute Force: O(1) or O(n) (depends on sort). Optimized: O(n) for the frequency map.

Watch Explanation

📊 Presentation (PPT)

📥 Download PPT

📎 Resources