Given a string s consisting of lowercase English letters, identify all characters whose first and last occurrences are at different positions.
For each such character, compute the sum of ASCII values of all characters that lie strictly between its first and last occurrence.
Return a list of all non-zero sums. The order of sums does not matter.
Examples:
Input: s = "abacab"
Output: [293, 294]
Explanation: characters 'a' and 'b' appear more than one:
'a' : between positions 1 and 5 → characters are b, a, c and ascii sum is 98 + 97 + 99 = 294.
'b' : between positions 2 and 6 → characters are a, c, a and ascii sum is 97 + 99 + 97 = 293.Input: s = "acdac"
Output: [197, 199]
Explanation: characters 'a' and 'c' appear more than one:
'a' : between positions 1 and 4 → characters are c, d and ascii sum is 99 + 100 = 199.
'c' : between positions 2 and 5 → characters are d, a and ascii sum is 100 + 97 = 197.
Table of Content
[Approach 1] - First-Last Index Brute Sum
In this approach, we first record the indices of all occurrences for each character in the string. For every character that appears more than once, we identify its first and last occurrence. Then, we traverse the substring strictly between these two positions and compute the sum of ASCII values of all characters in that range. Finally, we collect all such non-zero sums and return them. This method is simple but inefficient, as it may repeatedly scan large parts of the string for multiple characters.
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
vector<int> asciirange(string &s) {
// Store positions of each character
unordered_map<char, vector<int>> pos;
vector<int> result;
// Track all occurrences of each character
for (int i = 0; i < s.size(); i++) {
pos[s[i]].push_back(i);
}
for (auto it : pos) {
vector<int> idx = it.second;
// Proceed only if the character
// appears more than once
if (idx.size() >= 2) {
int first = idx[0];
int last = idx[idx.size() - 1];
int sum = 0;
// Compute ASCII sum of characters strictly
// between first and last occurrence
for (int i = first + 1; i < last; i++) {
sum += (int)s[i];
}
if(sum != 0){
result.push_back(sum);
}
}
}
return result;
}
int main() {
string s = "abacab";
vector<int> result = asciirange(s);
sort(result.begin(), result.end());
for (int i = 0; i < result.size(); i++) {
if (result[i] != 0)
cout << result[i] << " ";
}
return 0;
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;
class GfG {
public static ArrayList<Integer> asciirange(String s) {
// Store positions of each character
HashMap<Character, ArrayList<Integer>> pos = new HashMap<>();
ArrayList<Integer> result = new ArrayList<>();
// Track all occurrences of each character
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
pos.putIfAbsent(ch, new ArrayList<>());
pos.get(ch).add(i);
}
for (Map.Entry<Character, ArrayList<Integer>> it : pos.entrySet()) {
ArrayList<Integer> idx = it.getValue();
// Proceed only if the character
// appears more than once
if (idx.size() >= 2) {
int first = idx.get(0);
int last = idx.get(idx.size() - 1);
int sum = 0;
// Compute ASCII sum of characters strictly
// between first and last occurrence
for (int i = first + 1; i < last; i++) {
sum += (int) s.charAt(i);
}
if(sum != 0){
result.add(sum);
}
}
}
return result;
}
public static void main(String[] args) {
String s = "abacab";
ArrayList<Integer> result = asciirange(s);
Collections.sort(result);
for (int val : result) {
if (val != 0) {
System.out.print(val + " ");
}
}
}
}
def asciirange(s):
# Store positions of each character
pos = {}
result = []
# Track all occurrences of each character
for i in range(len(s)):
if s[i] not in pos:
pos[s[i]] = []
pos[s[i]].append(i)
for ch in pos:
idx = pos[ch]
# Proceed only if the character
# appears more than once
if len(idx) >= 2:
first = idx[0]
last = idx[-1]
sum_val = 0
# Compute ASCII sum of characters strictly
# between first and last occurrence
for i in range(first + 1, last):
sum_val += ord(s[i])
if sum_val !=0:
result.append(sum_val)
return result
if __name__ == "__main__":
s = "abacab"
result = asciirange(s)
result.sort()
for val in result:
if val != 0:
print(val, end=' ')
using System;
using System.Collections.Generic;
class GfG {
public static List<int> asciirange(string s) {
// Store positions of each character
Dictionary<char, List<int>> pos =
new Dictionary<char, List<int>>();
List<int> result = new List<int>();
// Track all occurrences of each character
for (int i = 0; i < s.Length; i++) {
char ch = s[i];
if (!pos.ContainsKey(ch)) {
pos[ch] = new List<int>();
}
pos[ch].Add(i);
}
foreach (var entry in pos) {
List<int> idx = entry.Value;
// Proceed only if the character
// appears more than once
if (idx.Count >= 2) {
int first = idx[0];
int last = idx[idx.Count - 1];
int sum = 0;
// Compute ASCII sum of characters strictly
// between first and last occurrence
for (int i = first + 1; i < last; i++) {
sum += (int)s[i];
}
if(sum != 0){
result.Add(sum);
}
}
}
return result;
}
static void Main() {
string s = "abacab";
List<int> result = asciirange(s);
result.Sort();
foreach (int val in result) {
if (val != 0) {
Console.Write(val + " ");
}
}
}
}
function asciirange(s) {
// Store positions of each character
const pos = {};
const result = [];
// Track all occurrences of each character
for (let i = 0; i < s.length; i++) {
const ch = s[i];
if (!pos[ch]) {
pos[ch] = [];
}
pos[ch].push(i);
}
for (const ch in pos) {
const idx = pos[ch];
// Proceed only if the character
// appears more than once
if (idx.length >= 2) {
const first = idx[0];
const last = idx[idx.length - 1];
let sum = 0;
// Compute ASCII sum of characters strictly
// between first and last occurrence
for (let i = first + 1; i < last; i++) {
sum += s.charCodeAt(i);
}
if(sum !== 0){
result.push(sum);
}
}
}
return result;
}
// Driver Code
const s = "abacab";
const result = asciirange(s);
result.sort((a, b) => a - b);
for (let i = 0; i < result.length; i++) {
if (result[i] !== 0) {
process.stdout.write(result[i] + " ");
}
}
Output
293 294
Time Complexity: O(n) where n is the length of string. Note that result vector will be of size 26 so ignore 26*log(26) while sorting.
Auxiliary space: O(n) storing the positions of each characters.
[Approach 2] Using Prefix Sum - O(n) Time and O(n) Space
The idea is to use prefix sums to quickly calculate the ASCII values between the first and last occurrences of each character in the string. We track these positions for each character, and use a prefix sum array to get the range sum in constant time. Only non-zero sums are collected. This makes the approach both efficient and easy to follow.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> asciirange(string &s) {
int n = s.size();
vector<int> pref(n + 1);
vector<int> v[26];
// Prefix sum and tracking first/last occurrences
for (int i = 1; i <= n; ++i) {
int idx = s[i - 1] - 'a';
if (v[idx].empty()) {
// first occurrence
v[idx].push_back(i);
// initially same as first
v[idx].push_back(i);
} else {
// update last occurrence
v[idx][1] = i;
}
// ASCII prefix sum
pref[i] = pref[i - 1] + s[i - 1];
}
vector<int> ans;
for (int i = 0; i < 26; ++i) {
if (!v[i].empty()) {
int fi = v[i][0], se = v[i][1];
if (fi != se) {
int sum = pref[se - 1] - pref[fi];
if (sum != 0)
ans.push_back(sum);
}
}
}
return ans;
}
int main() {
string s = "abacab";
vector<int> result = asciirange(s);
sort(result.begin(), result.end());
for (int val : result) {
cout << val << " ";
}
return 0;
}
import java.util.ArrayList;
import java.util.Collections;
class GFG {
public static ArrayList<Integer> asciirange(String s) {
int n = s.length();
int[] pref = new int[n + 1];
ArrayList<Integer>[] v = new ArrayList[26];
// Initialize lists
for (int i = 0; i < 26; ++i) {
v[i] = new ArrayList<>();
}
// Prefix sum and tracking first/last occurrences
for (int i = 1; i <= n; ++i) {
int idx = s.charAt(i - 1) - 'a';
if (v[idx].isEmpty()) {
// first occurrence
v[idx].add(i);
// initially same as first
v[idx].add(i);
} else {
// update last occurrence
v[idx].set(1, i);
}
// ASCII prefix sum
pref[i] = pref[i - 1] + s.charAt(i - 1);
}
ArrayList<Integer> ans = new ArrayList<>();
for (int i = 0; i < 26; ++i) {
if (!v[i].isEmpty()) {
int fi = v[i].get(0), se = v[i].get(1);
if (fi != se) {
int sum = pref[se - 1] - pref[fi];
if (sum != 0)
ans.add(sum);
}
}
}
return ans;
}
public static void main(String[] args) {
String s = "abacab";
ArrayList<Integer> result = asciirange(s);
Collections.sort(result);
for (int val : result) {
System.out.print(val + " ");
}
}
}
def asciirange(s):
n = len(s)
pref = [0] * (n + 1)
v = [[] for _ in range(26)]
# Prefix sum and tracking first/last occurrences
for i in range(1, n + 1):
idx = ord(s[i - 1]) - ord('a')
if not v[idx]:
# first occurrence
v[idx].append(i)
# initially same as first
v[idx].append(i)
else:
# update last occurrence
v[idx][1] = i
# ASCII prefix sum
pref[i] = pref[i - 1] + ord(s[i - 1])
ans = []
for i in range(26):
if v[i]:
fi, se = v[i][0], v[i][1]
if fi != se:
sum_val = pref[se - 1] - pref[fi]
if sum_val != 0:
ans.append(sum_val)
return ans
if __name__ == "__main__":
s = "abacab"
result = asciirange(s)
result.sort()
print(*result)
using System;
using System.Collections.Generic;
class GfG
{
public static List<int> asciirange(string s)
{
int n = s.Length;
int[] pref = new int[n + 1];
List<int>[] v = new List<int>[26];
// Initialize lists
for (int i = 0; i < 26; ++i)
{
v[i] = new List<int>();
}
// Prefix sum and tracking first/last occurrences
for (int i = 1; i <= n; ++i)
{
int idx = s[i - 1] - 'a';
if (v[idx].Count == 0)
{
// first occurrence
v[idx].Add(i);
// initially same as first
v[idx].Add(i);
}
else
{
// update last occurrence
v[idx][1] = i;
}
// ASCII prefix sum
pref[i] = pref[i - 1] + s[i - 1];
}
List<int> ans = new List<int>();
for (int i = 0; i < 26; ++i)
{
if (v[i].Count > 0)
{
int fi = v[i][0], se = v[i][1];
if (fi != se)
{
int sum = pref[se - 1] - pref[fi];
if (sum != 0)
ans.Add(sum);
}
}
}
return ans;
}
static void Main()
{
string s = "abacab";
List<int> result = asciirange(s);
result.Sort();
foreach (int val in result)
{
Console.Write(val + " ");
}
}
}
function asciirange(s) {
const n = s.length;
const pref = new Array(n + 1).fill(0);
const v = Array.from({ length: 26 }, () => []);
// Prefix sum and tracking first/last occurrences
for (let i = 1; i <= n; ++i) {
const idx = s.charCodeAt(i - 1) - 'a'.charCodeAt(0);
if (v[idx].length === 0) {
// first occurrence
v[idx].push(i);
// initially same as first
v[idx].push(i);
} else {
// update last occurrence
v[idx][1] = i;
}
// ASCII prefix sum
pref[i] = pref[i - 1] + s.charCodeAt(i - 1);
}
const ans = [];
for (let i = 0; i < 26; ++i) {
if (v[i].length > 0) {
const fi = v[i][0], se = v[i][1];
if (fi !== se) {
const sum = pref[se - 1] - pref[fi];
if (sum !== 0) {
ans.push(sum);
}
}
}
}
return ans;
}
//Driver Code
const s = "abacab";
const result = asciirange(s);
result.sort((a, b) => a - b);
console.log(result.join(" "));
Output
293 294
[Expected Approach] Space-Optimized Range Sum Using First and Last Indices - O(n) Time and O(1) Space
In this approach, we avoid using extra space like a prefix sum array by directly scanning character ranges when needed. We first record the first and last occurrence of each character using two fixed-size arrays (since there are only 26 lowercase letters). Then, for every character that appears more than once, we compute the sum of ASCII values of characters strictly between its first and last positions by iterating over that range.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> asciirange(string &s) {
vector<int> result;
vector<int> first(26, -1);
vector<int> last(26, -1);
int n = s.size();
// Track first and last
// occurrence of each character
for (int i = 0; i < n; i++) {
if (first[s[i] - 'a'] == -1) {
first[s[i] - 'a'] = i;
} else {
last[s[i] - 'a'] = i;
}
}
// Compute ASCII sums
// between first and last occurrence
for (int i = 0; i < 26; i++) {
if (first[i] != -1 && last[i] != -1) {
int sum = 0;
for (int j = first[i] + 1; j < last[i]; j++) {
sum += (int)s[j];
}
if(sum != 0)
result.push_back(sum);
}
}
return result;
}
int main() {
string s = "abacab";
vector<int> result = asciirange(s);
sort(result.begin(), result.end());
for (int i = 0; i < result.size(); i++) {
if (result[i] != 0) {
cout << result[i] << " ";
}
}
return 0;
}
import java.util.ArrayList;
import java.util.Collections;
class GfG {
public static ArrayList<Integer> asciirange(String s) {
ArrayList<Integer> result = new ArrayList<>();
int[] first = new int[26];
int[] last = new int[26];
int n = s.length();
// Initialize all indices to -1
for (int i = 0; i < 26; i++) {
first[i] = -1;
last[i] = -1;
}
// Track first and last
// occurrence of each character
for (int i = 0; i < n; i++) {
int idx = s.charAt(i) - 'a';
if (first[idx] == -1) {
first[idx] = i;
} else {
last[idx] = i;
}
}
// Compute ASCII sums
// between first and last occurrence
for (int i = 0; i < 26; i++) {
if (first[i] != -1 && last[i] != -1) {
int sum = 0;
for (int j = first[i] + 1; j < last[i]; j++) {
sum += (int) s.charAt(j);
}
if(sum != 0){
result.add(sum);
}
}
}
return result;
}
public static void main(String[] args) {
String s = "abacab";
ArrayList<Integer> result = asciirange(s);
Collections.sort(result);
for (int val : result) {
if (val != 0) {
System.out.print(val + " ");
}
}
}
}
def asciirange(s):
result = []
n = len(s)
# Initialize all indices to -1
first = [-1] * 26
last = [-1] * 26
# Track first and last
# occurrence of each character
for i in range(n):
idx = ord(s[i]) - ord('a')
if first[idx] == -1:
first[idx] = i
else:
last[idx] = i
# Compute ASCII sums
# between first and last occurrence
for i in range(26):
if first[i] != -1 and last[i] != -1:
sumval = 0
for j in range(first[i] + 1, last[i]):
sumval += ord(s[j])
if sumval!= 0:
result.append(sumval)
# Sort the results in increasing order
return result
if __name__ == "__main__":
s = "abacab"
result = asciirange(s)
result.sort()
for val in result:
if val != 0:
print(val, end=' ')
using System;
using System.Collections.Generic;
class GfG {
public static List<int> asciirange(string s) {
List<int> result = new List<int>();
int[] first = new int[26];
int[] last = new int[26];
int n = s.Length;
// Initialize all indices to -1
for (int i = 0; i < 26; i++) {
first[i] = -1;
last[i] = -1;
}
// Track first and last
// occurrence of each character
for (int i = 0; i < n; i++) {
int idx = s[i] - 'a';
if (first[idx] == -1)
{
first[idx] = i;
}
else
{
last[idx] = i;
}
}
// Compute ASCII sums
// between first and last occurrence
for (int i = 0; i < 26; i++) {
if (first[i] != -1 && last[i] != -1) {
int sum = 0;
for (int j = first[i] + 1; j < last[i]; j++) {
sum += (int)s[j];
}
if(sum != 0){
result.Add(sum);
}
}
}
return result;
}
static void Main() {
string s = "abacab";
List<int> result = asciirange(s);
result.Sort();
foreach (int val in result) {
if (val != 0)
{
Console.Write(val + " ");
}
}
}
}
function asciirange(s) {
const result = [];
const first = new Array(26).fill(-1);
const last = new Array(26).fill(-1);
const n = s.length;
// Track first and last
// occurrence of each character
for (let i = 0; i < n; i++) {
const idx = s.charCodeAt(i) - 97;
if (first[idx] === -1) {
first[idx] = i;
} else {
last[idx] = i;
}
}
// Compute ASCII sums
// between first and last occurrence
for (let i = 0; i < 26; i++) {
if (first[i] !== -1 && last[i] !== -1) {
let sum = 0;
for (let j = first[i] + 1; j < last[i]; j++) {
sum += s.charCodeAt(j);
}
if(sum !== 0){
result.push(sum);
}
}
}
return result;
}
// Driver Code
const s = "abacab";
const result = asciirange(s);
result.sort((a, b) => a - b);
for (let i = 0; i < result.length; i++) {
if (result[i] !== 0) {
process.stdout.write(result[i] + " ");
}
}
Output
293 294