Open In App

Longest Subsequence with same char as substrings and difference of frequency at most K

Improve
Improve
Like Article
Like
Save
Share
Report

Given a string  S of length N containing small-case English alphabets and an integer K, the task is to find the maximum possible length of the subsequence of S such that:

  • The frequency of each letter in the subsequence does not differ by more than K from the frequency of any other letter.
  • For any letter L that appears at least once, all occurrences of L must form a continuous segment.

Examples:

Input: S = “abba” , K = 1
Output: 3
Explanation: Subsequence “abb” and “bba” satisfies both the conditions.

Input: S = “aaa” , K = 2
Output: 3

Naive Approach: To solve the problem follow the below idea:

The brute force approach is to generate all subsequences and then check whether it meets all the conditions or not.

Follow the given steps to solve the given problem:

  • Generate all subsequences for a given string.
  • If the length of subsequence is greater than 0 then check whether equal characters are continuous or not (implemented as function isContinuous).
  • Again check whether the difference between maximum frequency and minimum frequency is less than k or not.
  • If the above two steps pass, then store the maximum length of all such subsequences. (say maxLen).
  • Return the maximum length maxLen as the final answer.

C++14




// C++ code to implement this approach
#include <bits/stdc++.h>
using namespace std;
 
int maxLen = 0;
 
// Function to check whether all the
// characters in the substring
// are continuous or not
bool isContinuous(string& temp)
{
    unordered_map<char, int> last_Pos;
    for (int i = 0; i < temp.length(); i++) {
        if (last_Pos[temp[i]]) {
            if (i - last_Pos[temp[i]] + 1 <= 1)
                last_Pos[temp[i]] = i + 1;
            else
                return 0;
        }
        else
            last_Pos[temp[i]] = i + 1;
    }
    return 1;
}
 
// Function to find the all the substrings
void generateSubSequences(string& str, string temp, int j,
                          int& k)
{
    unordered_map<char, int> freq;
    if (j == str.length()) {
        if (temp.length() > 0) {
            int minfreq = INT_MAX, maxfreq = INT_MIN;
            freq.clear();
            for (int i = 0; i < temp.length(); i++)
                freq[temp[i]]++;
 
            for (auto& x : freq) {
                minfreq = min(minfreq, x.second);
                maxfreq = max(maxfreq, x.second);
            }
 
            if (maxfreq - minfreq <= k
                && isContinuous(temp))
                maxLen = max(maxLen, (int)temp.length());
        }
        return;
    }
    generateSubSequences(str, temp, j + 1, k);
    temp.push_back(str[j]);
    generateSubSequences(str, temp, j + 1, k);
}
 
// Driver's code
int main()
{
    string str = "abba", temp;
    int k = 1;
    generateSubSequences(str, temp, 0, k);
    cout << maxLen;
    return 0;
}


Java




// Java code for the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    static int maxLen = 0;
 
    // Function to check whether all the characters in the
    // substring are continuous or not
    static boolean iscontinuous(String temp)
    {
        Map<Character, Integer> last_Pos = new HashMap<>();
        for (int i = 0; i < temp.length(); i++) {
            if (last_Pos.containsKey(temp.charAt(i))) {
                if (i - last_Pos.get(temp.charAt(i)) + 1
                    <= 1) {
                    last_Pos.put(
                        temp.charAt(i),
                        last_Pos.get(temp.charAt(i)) + 1);
                }
                else {
                    return false;
                }
            }
            else {
                last_Pos.put(
                    temp.charAt(i),
                    last_Pos.getOrDefault(temp.charAt(i), 0)
                        + 1);
            }
        }
        return true;
    }
 
    // Function to find the all the substrings
    static void generateSubSequences(String str,
                                     String temp, int j,
                                     int k)
    {
        HashMap<Character, Integer> freq = new HashMap<>();
        if (j == str.length()) {
            if (temp.length() > 0) {
                int minfreq = Integer.MAX_VALUE,
                    maxfreq = Integer.MIN_VALUE;
                freq.clear();
                for (int i = 0; i < temp.length(); i++) {
                    freq.put(
                        temp.charAt(i),
                        freq.getOrDefault(temp.charAt(i), 0)
                            + 1);
                }
 
                for (int i : freq.values()) {
                    minfreq = Math.min(minfreq, i);
                    maxfreq = Math.max(maxfreq, i);
                }
 
                if (maxfreq - minfreq <= k
                    && iscontinuous(temp)) {
                    maxLen = Math.max(maxLen,
                                      (int)temp.length());
                }
            }
            return;
        }
        generateSubSequences(str, temp, j + 1, k);
        temp += str.charAt(j);
        generateSubSequences(str, temp, j + 1, k);
    }
 
    public static void main(String[] args)
    {
        String str = "abba", temp = "";
        int k = 1;
 
        generateSubSequences(str, temp, 0, k);
        System.out.print(maxLen);
    }
}
 
// This code is contributed by lokeshmvs21.


Python3




# Python code to implement this approach
maxLen = 0
 
# Function to check whether all the
# characters in the substring
# are continuous or not
def isContinuous(temp):
    last_Pos = {}
    for i in range(len(temp)):
        if temp[i] in last_Pos:
            if i - last_Pos[temp[i]] + 1 <= 1:
                last_Pos[temp[i]] = i + 1
            else:
                return False
        else:
            last_Pos[temp[i]] = i + 1
    return True
 
# Function to find the all the substrings
def generateSubSequences(str, temp, j, k):
    freq = {}
 
    if j == len(str):
        if len(temp) > 0:
            minfreq = float('inf')
            maxfreq = float('-inf')
 
            freq.clear()
 
            for i in range(len(temp)):
                if (temp[i] in freq):
                    freq[temp[i]] += 1
                else:
                    freq[temp[i]] = 1
 
            for key, value in freq.items():
                minfreq = min(minfreq, value)
                maxfreq = max(maxfreq, value)
 
            if maxfreq - minfreq <= k and isContinuous(temp):
                global maxLen
                maxLen = max(maxLen, len(temp))
 
        return
 
    generateSubSequences(str, temp, j + 1, k)
    temp += str[j]
    generateSubSequences(str, temp, j + 1, k)
 
# Driver's code
if __name__ == '__main__':
    str = "abba"
    temp = ""
    k = 1
    generateSubSequences(str, temp, 0, k)
    print(maxLen)
 
# This code is contributed by Tapesh(tapeshdua420)


C#




// Include namespace system
using System;
using System.Collections.Generic;
 
using System.Collections;
 
 
 
public class GFG
{
  public static int maxLen = 0;
  // Function to check whether all the characters in the
  // substring are continuous or not
  public static bool iscontinuous(String temp)
  {
    var last_Pos = new Dictionary<char, int>();
    for (int i = 0; i < temp.Length; i++)
    {
      if (last_Pos.ContainsKey(temp[i]))
      {
        if (i - last_Pos[temp[i]] + 1 <= 1)
        {
          last_Pos[temp[i]] = last_Pos[temp[i]] + 1;
        }
        else
        {
          return false;
        }
      }
      else
      {
        last_Pos[temp[i]] = (last_Pos.ContainsKey(temp[i]) ? last_Pos[temp[i]] : 0) + 1;
      }
    }
    return true;
  }
  // Function to find the all the substrings
  public static void generateSubSequences(String str, String temp, int j, int k)
  {
    var freq = new Dictionary<char, int>();
    if (j == str.Length)
    {
      if (temp.Length > 0)
      {
        var minfreq = int.MaxValue;
        var maxfreq = int.MinValue;
        freq.Clear();
        for (int i = 0; i < temp.Length; i++)
        {
          freq[temp[i]] = (freq.ContainsKey(temp[i]) ? freq[temp[i]] : 0) + 1;
        }
        foreach (int i in freq.Values)
        {
          minfreq = Math.Min(minfreq,i);
          maxfreq = Math.Max(maxfreq,i);
        }
        if (maxfreq - minfreq <= k && GFG.iscontinuous(temp))
        {
          GFG.maxLen = Math.Max(GFG.maxLen,(int)temp.Length);
        }
      }
      return;
    }
    GFG.generateSubSequences(str, temp, j + 1, k);
    temp += str[j];
    GFG.generateSubSequences(str, temp, j + 1, k);
  }
  public static void Main(String[] args)
  {
    var str = "abba";
    var temp = "";
    var k = 1;
    GFG.generateSubSequences(str, temp, 0, k);
    Console.Write(GFG.maxLen);
  }
}
 
// This code is contributed by aadityaburujwale.


Javascript




// JS code to implement this approach
 
let maxLen = 0;
 
// Function to check whether all the
// characters in the substring
// are continuous or not
function isContinuous(temp)
{
    let last_Pos = new Map();
 
    for (let i=97;i<=122;i++)
    {
        last_Pos.set(String.fromCharCode(i),0);
    }
 
    for (let i = 0; i < temp.length; i++) {
        if (last_Pos.get(temp[i])) {
            if (i - last_Pos.get(temp[i]) + 1 <= 1)
                last_Pos.set(temp[i] , i + 1);
            else
                return 0;
        }
        else
            last_Pos.set(temp[i] , i + 1);
    }
    return 1;
}
 
// Function to find the all the substrings
function generateSubSequences(str, temp, j, k)
{
    let freq = new Map();
 
    for (let i=97;i<=122;i++)
    {
        freq.set(String.fromCharCode(i), 0);
    }
    if (j == str.length) {
        if (temp.length > 0) {
            let minfreq = Number.MAX_VALUE, maxfreq = Number.MIN_VALUE;
            freq.clear();
            for (let i = 0; i < temp.length; i++)
                freq[temp[i]]++;
 
            for (let [key, value] of freq) {
                minfreq = Math.min(minfreq, value);
                maxfreq = Math.max(maxfreq, value);
            }
                 
 
            if (maxfreq - minfreq <= k
                && isContinuous(temp))
                maxLen = Math.max(maxLen, temp.length);
        }
        return;
    }
    generateSubSequences(str, temp, j + 1, k);
    temp+=str[j];
    generateSubSequences(str, temp, j + 1, k);
}
 
// Driver's code
let str = "abba", temp = "";
let k = 1;
generateSubSequences(str, temp, 0, k);
console.log(maxLen);
 
// This code is contributed by akashish__.


Output

3

Time Complexity: O(N*2N)
Auxiliary Space: O(N)



Last Updated : 16 Dec, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads