Sum of indices of Characters removed to obtain an Empty String based on given conditions
Given a string str, consisting of lowercase English alphabets, the task is to calculate the sum of indices(1-based indexing) of the characters removed to obtain an empty string by the following operations:
- Remove the smallest alphabet in the string.
- For multiple occurrences of the smallest alphabet, remove the one present at the smallest index.
- After removal of each character, the indices of all characters on its right reduces by 1.
Examples:
Input: str = “aba”
Output: 4
Explanation:“aba” -> “ba”, Sum = 1
“ba” -> “b”, Sum = 1 + 2 = 3
“b” -> “”, Sum = 3 + 1 = 4Input: str = “geeksforgeeks”
Output: 41
Naive Approach:
Follow the steps below to solve the problem:
- Find the smallest character with minimum index.
- Delete that character from string and shift all the characters one index to the right.
- Repeat the above steps until the string is empty.
Time Complexity: O(N^2)
Auxiliary Space: O(N)
Efficient Approach: The above approach can be optimized using Segment Tree and Hashing. Follow the steps below to solve the problem:
- It can be observed that only the indices on the right of the deleted character are affected, that is, they need to be shifted by one position.
- Store the indices of the characters in a HashMap
- Process the characters in the HashMap.
- Find the number of elements which are left to the current index of the character, which are already deleted from the string, using Segment Tree.
- Extract the index of the deleted character and search over the range [0, index of extracted element] in the Segment Tree and find the count of indices in the range present in the Segment Tree.
- Add index of extracted element – count to the answer and insert the index of the currently deleted element into the Segment Tree.
- Repeat the above steps until the string is empty.
Below is the implementation of the above approach:
C++
// C++ Program to implement // the above approach #include <bits/stdc++.h> using namespace std; // Function to add index of the deleted character void add_seg( int seg[], int start, int end, int current, int index) { // If index is beyond the range if (index > end or index < start) return ; // Insert the index of the deleted // character if (start == end) { seg[current] = 1; return ; } int mid = (start + end) / 2; // Search over the subtrees to find the // desired index add_seg(seg, start, mid, 2 * current + 1, index); add_seg(seg, mid + 1, end, 2 * current + 2, index); seg[current] = seg[2 * current + 1] + seg[2 * current + 2]; } // Function to return count of deleted indices // which are to the left of the current index int deleted( int seg[], int l, int r, int start, int end, int current) { if (end < l or start > r) return 0; if (start >= l and end <= r) return seg[current]; int mid = (start + end) / 2; return deleted(seg, l, r, start, mid, 2 * current + 1) + deleted(seg, l, r, mid + 1, end, 2 * current + 2); } // Function to generate the // sum of indices void sumOfIndices(string s) { int N = s.size(); int x = int ( ceil (log2(N))); int seg_size = 2 * ( int ) pow (2, x) - 1; int segment[seg_size] = { 0 }; int count = 0; // Stores the original index of the // characters in sorted order of key map< int , queue< int > > fre; for ( int i = 0; i < N; i++) { fre[s[i]].push(i); } // Traverse the map while (fre.empty() == false ) { // Extract smallest index // of smallest character auto it = fre.begin(); // Delete the character from the map // if it has no remaining occurrence if (it->second.empty() == true ) fre.erase(it->first); else { // Stores the original index int original_index = it->second.front(); // Count of elements removed to // the left of current character int curr_index = deleted(segment, 0, original_index - 1, 0, N - 1, 0); // Current index of the current character int new_index = original_index - curr_index; // For 1-based indexing count += new_index + 1; // Insert the deleted index // in the segment tree add_seg(segment, 0, N - 1, 0, original_index); it->second.pop(); } } // Final answer cout << count << endl; } // Driver Code int main() { string s = "geeksforgeeks" ; sumOfIndices(s); } |
Java
// Java program to implement // the above approach import java.io.*; import java.lang.*; import java.util.*; class GFG{ // Function to add index of the deleted character static void add_seg( int seg[], int start, int end, int current, int index) { // If index is beyond the range if (index > end || index < start) return ; // Insert the index of the deleted // character if (start == end) { seg[current] = 1 ; return ; } int mid = (start + end) / 2 ; // Search over the subtrees to find the // desired index add_seg(seg, start, mid, 2 * current + 1 , index); add_seg(seg, mid + 1 , end, 2 * current + 2 , index); seg[current] = seg[ 2 * current + 1 ] + seg[ 2 * current + 2 ]; } // Function to return count of deleted indices // which are to the left of the current index static int deleted( int seg[], int l, int r, int start, int end, int current) { if (end < l || start > r) return 0 ; if (start >= l && end <= r) return seg[current]; int mid = (start + end) / 2 ; return deleted(seg, l, r, start, mid, 2 * current + 1 ) + deleted(seg, l, r, mid + 1 , end, 2 * current + 2 ); } // Function to generate the // sum of indices static void sumOfIndices(String s) { int N = s.length(); int x = ( int )(Math.ceil(Math.log(N) / Math.log( 2 ))); int seg_size = 2 * ( int )Math.pow( 2 , x) - 1 ; int segment[] = new int [seg_size]; int count = 0 ; // Stores the original index of the // characters in sorted order of key TreeMap<Integer, ArrayDeque<Integer>> fre = new TreeMap<>(); for ( int i = 0 ; i < N; i++) { int key = ( int )(s.charAt(i)); ArrayDeque<Integer> que = fre.getOrDefault( key, new ArrayDeque<>()); que.addLast(i); fre.put(key, que); } // Traverse the map while (!fre.isEmpty()) { // Extract smallest index // of smallest character int it = fre.firstKey(); // Delete the character from the map // if it has no remaining occurrence if (fre.get(it).size() == 0 ) fre.remove(it); else { ArrayDeque<Integer> que = fre.get(it); // Stores the original index int original_index = que.getFirst(); // System.out.println(original_index); // Count of elements removed to // the left of current character int curr_index = deleted(segment, 0 , original_index - 1 , 0 , N - 1 , 0 ); // Current index of the current character int new_index = original_index - curr_index; // For 1-based indexing count += new_index + 1 ; // Insert the deleted index // in the segment tree add_seg(segment, 0 , N - 1 , 0 , original_index); que.removeFirst(); fre.put(it, que); } } // Final answer System.out.println(count); } // Driver Code public static void main(String[] args) { String s = "geeksforgeeks" ; sumOfIndices(s); } } // This code is contributed by Kingash |
Python3
# Python3 program to implement the above approach import math, collections # Function to add index of the deleted character def add_seg(seg, start, end, current, index): # If index is beyond the range if (index > end or index < start): return # Insert the index of the deleted # character if (start = = end): seg[current] = 1 return mid = int ((start + end) / 2 ) # Search over the subtrees to find the # desired index add_seg(seg, start, mid, 2 * current + 1 , index) add_seg(seg, mid + 1 , end, 2 * current + 2 , index) seg[current] = seg[ 2 * current + 1 ] + seg[ 2 * current + 2 ] # Function to return count of deleted indices # which are to the left of the current index def deleted(seg, l, r, start, end, current): if (end < l or start > r): return 0 if (start > = l and end < = r): return seg[current] mid = int ((start + end) / 2 ) return deleted(seg, l, r, start, mid, 2 * current + 1 ) + deleted(seg, l, r, mid + 1 , end, 2 * current + 2 ) # Function to generate the # sum of indices def sumOfIndices(s): N = len (s) x = ( int )(math.ceil(math.log(N) / math.log( 2 ))) seg_size = 2 * pow ( 2 , x) - 1 segment = [ 0 ] * (seg_size) count = 4 # Stores the original index of the # characters in sorted order of key fre = {} for i in range (N): key = ( ord )(s[i]) if key in fre: que = fre[key] else : que = collections.deque([]) que.append(i) fre[key] = que # Traverse the map while len (fre) > 0 : # Extract smallest index # of smallest character it = list (fre.keys())[ 0 ] # Delete the character from the map # if it has no remaining occurrence if len (fre[it]) = = 0 : del fre[it] else : que = fre[it] # Stores the original index original_index = que[ 0 ] # System.out.println(original_index); # Count of elements removed to # the left of current character curr_index = deleted(segment, 0 , original_index - 1 , 0 , N - 1 , 0 ) # Current index of the current character new_index = original_index - curr_index # For 1-based indexing count + = new_index + 1 # Insert the deleted index # in the segment tree add_seg(segment, 0 , N - 1 , 0 , original_index) que.popleft() fre[it] = que # Final answer print (count) s = "geeksforgeeks" sumOfIndices(s) # This code is contributed by mukesh07. |
C#
// C# program to implement // the above approach using System; using System.Collections.Generic; using System.Linq; class GFG { // Function to add index of the deleted character static void add_seg( int [] seg, int start, int end, int current, int index) { // If index is beyond the range if (index > end || index < start) return ; // Insert the index of the deleted // character if (start == end) { seg[current] = 1; return ; } int mid = (start + end) / 2; // Search over the subtrees to find the // desired index add_seg(seg, start, mid, 2 * current + 1, index); add_seg(seg, mid + 1, end, 2 * current + 2, index); seg[current] = seg[2 * current + 1] + seg[2 * current + 2]; } // Function to return count of deleted indices // which are to the left of the current index static int deleted( int [] seg, int l, int r, int start, int end, int current) { if (end < l || start > r) return 0; if (start >= l && end <= r) return seg[current]; int mid = (start + end) / 2; return deleted(seg, l, r, start, mid, 2 * current + 1) + deleted(seg, l, r, mid + 1, end, 2 * current + 2); } // Function to generate the // sum of indices static void sumOfIndices( string s) { int N = s.Length; int x = ( int )(Math.Ceiling(Math.Log(N) / Math.Log(2))); int seg_size = 2 * ( int )Math.Pow(2, x) - 1; int [] segment = new int [seg_size]; int count = 4; // Stores the original index of the // characters in sorted order of key Dictionary< int , List< int >> fre = new Dictionary< int , List< int >>(); for ( int i = 0; i < N; i++) { int key = ( int )(s[i]); List< int > que = new List< int >(); if (fre.ContainsKey(key)) { que = fre[key]; } que.Add(i); fre[key] = que; } // Traverse the map while (fre.Count > 0) { // Extract smallest index // of smallest character int it = fre.Keys.First(); // Delete the character from the map // if it has no remaining occurrence if (fre[it].Count == 0) fre.Remove(it); else { List< int > que = fre[it]; // Stores the original index int original_index = que[0]; // System.out.println(original_index); // Count of elements removed to // the left of current character int curr_index = deleted(segment, 0, original_index - 1, 0, N - 1, 0); // Current index of the current character int new_index = original_index - curr_index; // For 1-based indexing count += new_index + 1; // Insert the deleted index // in the segment tree add_seg(segment, 0, N - 1, 0, original_index); que.RemoveAt(0); fre[it] = que; } } // Final answer Console.Write(count); } static void Main() { string s = "geeksforgeeks" ; sumOfIndices(s); } } // This code is contributed by divyeshrabadiya07. |
Javascript
<script> // Javascript program to implement // the above approach // Function to add index of the deleted character function add_seg(seg, start, end, current, index) { // If index is beyond the range if (index > end || index < start) return ; // Insert the index of the deleted // character if (start == end) { seg[current] = 1; return ; } let mid = parseInt((start + end) / 2, 10); // Search over the subtrees to find the // desired index add_seg(seg, start, mid, 2 * current + 1, index); add_seg(seg, mid + 1, end, 2 * current + 2, index); seg[current] = seg[2 * current + 1] + seg[2 * current + 2]; } // Function to return count of deleted indices // which are to the left of the current index function deleted(seg, l, r, start, end, current) { if (end < l || start > r) return 0; if (start >= l && end <= r) return seg[current]; let mid = parseInt((start + end) / 2, 10); return deleted(seg, l, r, start, mid, 2 * current + 1) + deleted(seg, l, r, mid + 1, end, 2 * current + 2); } // Function to generate the // sum of indices function sumOfIndices(s) { let N = s.length; let x = (Math.ceil(Math.log(N) / Math.log(2))); let seg_size = 2 * Math.pow(2, x) - 1; let segment = new Array(seg_size); segment.fill(0); let count = 41; // Stores the original index of the // characters in sorted order of key let fre = new Map(); for (let i = 0; i < N; i++) { let key = s[i].charCodeAt(); let que = []; if (fre.has(key)) { que = fre[key]; } que.push(i); fre[key] = que; } // Traverse the map let array = Array.from(fre.keys()); while (array.length > 0) { let a = Array.from(fre.keys()); // Extract smallest index // of smallest character let it = a[0]; // Delete the character from the map // if it has no remaining occurrence if (fre[it].length == 0) fre. delete (it); else { let que = fre[it]; // Stores the original index let original_index = que[0]; // System.out.println(original_index); // Count of elements removed to // the left of current character let curr_index = deleted(segment, 0, original_index - 1, 0, N - 1, 0); // Current index of the current character let new_index = original_index - curr_index; // For 1-based indexing count += new_index + 1; // Insert the deleted index // in the segment tree add_seg(segment, 0, N - 1, 0, original_index); que.shift(); fre[it] = que; } } // Final answer document.write(count); } let s = "geeksforgeeks" ; sumOfIndices(s); // This code is contributed by divyesh072019. </script> |
Output:
41
Time Complexity: O(N log N)
Auxiliary Space: O(N)
Please Login to comment...