Longest Harmonious Subsequence in Java

An array of n integers is given to us. The task is to find the size of the longest harmonious subsequence of the array. A subsequence is said to be harmonious if the difference between the maximum value element and the minimum value element in the subsequence is 1.

Example 1:

Input

int inArr1[] = {11, 12, 12, 13, 14, 15, 11, 11, 11, 11}

Output

7

Explanation:

The longest harmonious subsequence is {11, 12, 12, 11, 11, 11, 11} whose size is 7. Hence, the output is 7.

Example 2:

Input

int inArr1[] = {0, 1, 5, 8, 10, 19, 15, 25, 30, 40, 45, 7, 11}

Output

2

Explanation:

The longest harmonious subsequences are {0, 1} or {7, 8}, and {10, 11}. Each harmonious subsequence is of size 2. Hence, the output is 2.

Brute Force Approach: Using Bit Masking

The concept is to generate all of the possible subsequences with the help of the bit masking technique. For every subsequence, check whether the subsequence is the Harmonious subsequence or not. Take out the maximum length of all of the valid subsequences that are possible.

Observe the following steps:

Step 1: Take a variable ans. Initialize it with the value 0. The variable "ans" will contain the final answer.

Step 2: Iterate from 'j' = 0 to '2len - 1', where 'len is the length of the input array, 'inputArr[]'.

  • Initialize three integers 'minVal, 'maxVal', and 'currLen' with INT_MAX, INT_MIN, and 0, respectively, for keeping the minimum and maximum values of the current subsequence and the length of the current subsequence respectively.
  • Iterate from 'k' = 0 to 'len - 1':
    • If a kth bit of j is set and 'MIN_VALUE' is < inputArr[k], then update the 'MIN_VALUE' to inputArr[k].
    • If a kth bit of j is set and 'MAX_VALUE' is > inputArr[k], then update the 'MAX_VALUE' to inputArr[k].
    • Increment the 'currLen' since we are considering the current element in the subsequence.
  • If the difference between the 'MIN_VALUE' and 'MAX_VALUE' is 1, then it is a valid subsequence. Therefore, update the 'ans' to the maximum of 'ans' and 'currLen'.

Step 3: Return the answer 'ans'.

Now, let's observe the implementation of the above algorithm.

FileName: LongestHarmoniousSubsequence.java

Output:

For the input array: 
11 12 12 13 14 15 11 11 11 11 
The length of the longest Harmonic subsequence is: 7


For the input array: 
0 1 5 8 10 19 15 25 30 40 45 7 11 
The length of the longest Harmonic subsequence is: 2

Complexity Analysis: The program is generation all of the binary values from 0 to 2len - 1. After that, the program is iteration through the array. Therefore, the overall time complexity of the program is O(len x 2len), where 'len' is the length of the input array. Also, the program is not using extra space, making the space complexity of the program O(1).

The time complexity of the program clearly indicates that it is not suitable for larger inputs. Therefore, it is required to do some optimization to reduce the time complexity.

Optimization

The concept is to pivot every element of the array and then take only those elements that are equal or have a difference of 1 such that the maximum difference in the subsequence becomes 1.

Observe the following steps.

Step 1: Take a variable ans. Initialize it with the value 0. The variable "ans" will contain the final answer.

Step 2: Iterate from 'j' = 0 to 'len - 1':

  • Initialize 'currLen' with 0. The variable 'currLen' is used to keep the length of the current subsequence.
  • Take a Boolean flag 'flg' and assign a value false to it, and the value will be true if there is a possibility to make a harmonic subsequence.
  • Iterate from 'k' = 0 to 'len - 1':
    • If the element at the kth index is the same as the element at the jth index, then increase the 'currLen' by 1.
    • If the element at the kth index is 1 larger than the element at the jth index, then increase the 'currLen' by 1 and set the flag 'flg' to true as the maximum difference of the current subsequence is 1.
  • If the flag 'flg' is true, then update the answer 'ans' to the maximum of 'ans' and 'currLen'.

Step 3: Return 'ans' as the final answer.

Now, let's observe the implementation of the above algorithm.

FileName: LongestHarmonioussubsequence1.java

Output:

For the input array: 
11 12 12 13 14 15 11 11 11 11 
The length of the longest Harmonic subsequence is: 7


For the input array: 
0 1 5 8 10 19 15 25 30 40 45 7 11 
The length of the longest Harmonic subsequence is: 2

Complexity Analysis: In the program, each element of the input array is getting pivoted. Also, a loop is iterating through the array that takes O(len) time. Thus, the overall time complexity of the program O(len2), where 'len' is the size of the input array. The space complexity of the program is constant, i.e., O(1).

Another Approach: Using HashMap

The approach is to keep the number of times an element occurs in a HashMap. In every iteration, check two things:

  • Check whether inputArr[j] + 1 is there in the HashMap or not. If it is present, then the current length of the subsequence will be the total number of occurrences of inputArr[j] + the total number of occurrences of (inputArr[j] + 1).
  • Check whether inputArr[j] - 1 is there in the HashMap or not. If it is present, then the current length of the subsequence will be the number of occurrences of inputArr[j] + the total number of occurrences of (inputArr[j] - 1).

The steps are as follows:

Step 1: Take a variable ans. Initialize it with the value 0. The variable "ans" will contain the final answer.

Step 2: Define a HashMap 'freqHashMap' for keeping the number of times each element is occurring in the input array inputArr[].

Step 3: Iterate from 'j' = 0 to 'len - 1':

  • Increase the count of inputArr[j] in the HashMap.
  • If inputArr[j] + 1 is present in the HashMap, i.e., freqHashMap[inputArr[j] + 1] >0, then update the 'ans' to the maximum of 'ans' and (freqHashMap [inputArr[j]] + freqHashMap[inputArr[j] + 1]).
  • If inputArr[j] - 1 is present in the HashMap, i.e., freqHashMap[inputArr[j] - 1] >0, then update the 'ans' to the maximum of 'ans' and (freqHashMap[inputArr[j]] + freqHashMap[inputArr[j] - 1]).

Step 4: return 'ans'.

The following program implements the above-mentioned steps.

FileName: LongestHarmonioussubsequence2.java

Output:

For the input array: 
11 12 12 13 14 15 11 11 11 11 
The length of the longest Harmonic subsequence is: 7


For the input array: 
0 1 5 8 10 19 15 25 30 40 45 7 11 
The length of the longest Harmonic subsequence is: 2

Complexity Analysis: In program, a loop is used to iterate over the input array and incrementing the count of each element in the HashMap that has the amortized time complexity of O(1). Therefore, the overall time complexity of the program is O(N). Also, the HashMap can grow maximum up to the size of the input array. Therefore, the overall space complexity of the program also O(N). Here, N is the total number of elements in the input array.