Longest Alternating Subsequence

Longest Alternating Subsequence 

Problem Statement

You are given:

  • An array of distinct strings words[]

  • A binary array groups[] (values 0 or 1), same length as words

Find the longest subsequence of words where consecutive elements have alternating groups values. Return any one such longest subsequence.

Example

Input:

words = ["a", "b", "c", "d"] groups = [1, 0, 1, 1]

Output:

["a", "b", "c"]

Best Data Structure for the Job

Simple arrays and lists work well. Since groups contains only 0 or 1, no complex data structures are required.

Different Approaches

1. Brute Force — Try All Subsequences (Exponential Time)

Enumerate all subsequences, check if their groups alternate, and return the longest.

public List<String> bruteForceLongestAltSubseq(String[] words, int[] groups) { List<String> result = new ArrayList<>(); int n = words.length; int maxLen = 0; // Use bitmask to generate all subsequences for (int mask = 1; mask < (1 << n); mask++) { List<String> subseq = new ArrayList<>(); int prevGroup = -1; boolean valid = true; for (int i = 0; i < n; i++) { if (((mask >> i) & 1) == 1) { if (prevGroup == -1 || groups[i] != prevGroup) { subseq.add(words[i]); prevGroup = groups[i]; } else { valid = false; break; } } } if (valid && subseq.size() > maxLen) { maxLen = subseq.size(); result = subseq; } } return result; }

2. Dynamic Programming — O(n²) Time

Compute the longest alternating subsequence length ending at each index, and reconstruct the subsequence.

public List<String> dpLongestAltSubseq(String[] words, int[] groups) { int n = words.length; int[] dp = new int[n]; // Length of LAS ending at i int[] parent = new int[n]; // To reconstruct the path Arrays.fill(dp, 1); Arrays.fill(parent, -1); int maxLen = 1, maxIndex = 0; for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { if (groups[i] != groups[j] && dp[j] + 1 > dp[i]) { dp[i] = dp[j] + 1; parent[i] = j; } } if (dp[i] > maxLen) { maxLen = dp[i]; maxIndex = i; } } // Reconstruct subsequence List<String> result = new ArrayList<>(); int curr = maxIndex; while (curr != -1) { result.add(words[curr]); curr = parent[curr]; } Collections.reverse(result); return result; }

3. Greedy Linear Scan — O(n) Time (Optimized)

Build subsequences greedily from two possible starting points (starting from first element and from first element with opposite group), then pick the longer one.

public List<String> greedyLongestAltSubseq(String[] words, int[] groups) { List<String> subsequence1 = buildSubsequence(words, groups, 0); int alternateStart = -1; for (int i = 1; i < groups.length; i++) { if (groups[i] != groups[0]) { alternateStart = i; break; } } if (alternateStart == -1) { return subsequence1; // All groups are the same } List<String> subsequence2 = buildSubsequence(words, groups, alternateStart); return subsequence1.size() >= subsequence2.size() ? subsequence1 : subsequence2; } private List<String> buildSubsequence(String[] words, int[] groups, int start) { List<String> result = new ArrayList<>(); result.add(words[start]); int lastGroup = groups[start]; for (int i = start + 1; i < groups.length; i++) { if (groups[i] != lastGroup) { result.add(words[i]); lastGroup = groups[i]; } } return result; }

⚠️Common Pitfalls

  • Confusing subsequence with substring; subsequences can skip elements.

  • Failing to consider alternate starting points for maximum subsequence length.

  • Assuming groups can have values other than 0 or 1.

📊Complexity Summary

Approach          Time Complexity    Space Complexity
Brute Force            O(2^n)    O(n)
Dynamic Programming            O(n²)    O(n)
Greedy Linear Scan            O(n)    O(n)

🌍Real-World Use Cases

  • Scheduling alternating tasks or shifts (e.g., alternating day/night shifts).

  • Communication protocols with toggling signal patterns.

  • Pattern recognition where alternating states are important.

  • Turn-based game mechanics where players alternate moves.


I hope you found this article insightful! Keep exploring, keep learning, and don’t forget to check back daily for more exciting problem breakdowns. If you know someone who would benefit from this, share it with them and help them grow too! That’s it for today—see you in the next post!

                                                                                                                                         Signing off!! 

                                                                                                Master DSA One Problem at a Time :)

Comments

Popular posts from this blog

Trailing Zeros in Factorial – How Many and Why?

Divisible Drama — Who’s In, Who’s Out?

Zero Array After Queries