Strings in C++: Longest Palindrome and Sentence Reconstruction
This chapter explores two fundamental string processing techniques in C++: frequency-based character distribution for constructing palindromes and tokenization with positional bucket mapping to reconstruct jumbled sentences.
1. Problem 1: Longest Palindrome — Concept and Problem Breakdown
A palindrome is a string that reads identically forward and backward.
Examples of Palindromes
"naman"forward:"naman", backward:"naman"(Valid)"mom"forward:"mom", backward:"mom"(Valid)"rohit"forward:"rohit", backward:"tihor"(Invalid)
Problem Statement
Given a string s containing lowercase ('a'–'z') and uppercase ('A'–'Z') English letters, determine the length of the longest palindrome that can be built using the characters from s.
Key Constraint: Case sensitivity matters.
'A'and'a'are distinct characters and cannot be paired together to form symmetrical flanks.
Example Walkthrough
Given input string :
- We can choose four
'c's, two'd's, and one'a'(or'b'). - Constructed palindrome:
"dccaccd"(length = ). - The max length return value is
7.
2. Core Mental Model: Symmetrical Palindrome Structure
To build the longest possible palindrome from an arbitrary collection of characters, we must analyze how character frequencies map onto symmetrical string positions.
Mathematical Pattern Rules
- Even Frequency Characters: If a character appears an even number of times (), all occurrences can be fully utilized symmetrically (half placed on the left side, half on the right side).
- Odd Frequency Characters: If a character appears an odd number of times (), we can use its largest even component () symmetrically. The remaining character cannot be paired.
- The Center Element Exception: A palindrome can contain at most one single unpaired character at its exact geometric center. Therefore, among all characters that appear an odd number of times, exactly one single extra character can be added to the overall length.
3. Frequency Bucket Strategy (Handling Case Sensitivity)
To track character counts without hash map overhead, we allocate two fixed-size frequency vectors of size 26:
lower: Stores counts for'a'through'z'(mapped to indices0through25).upper: Stores counts for'A'through'Z'(mapped to indices0through25).
ASCII Mapping Index Formula
- For lowercase characters:
index = ch - 'a'(where ASCII'a'= 97) - For uppercase characters:
index = ch - 'A'(where ASCII'A'= 65)
4. Longest Palindrome: Step-by-Step Flow Algorithm
5. Longest Palindrome: Complete C++ Implementation
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution {
public:
int longestPalindrome(string s) {
// Step 1: Create frequency arrays for lowercase and uppercase characters
vector<int> lower(26, 0);
vector<int> upper(26, 0);
// Step 2: Populate frequency maps using ASCII offsets
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a') {
lower[s[i] - 'a']++;
} else {
upper[s[i] - 'A']++;
}
}
int count = 0;
bool isOddPresent = false;
// Step 3: Accumulate valid symmetrical character lengths
for (int i = 0; i < 26; i++) {
// Lowercase processing
if (lower[i] % 2 == 0) {
count += lower[i];
} else {
count += lower[i] - 1; // Take even portion
isOddPresent = true; // Mark that an odd element exists
}
// Uppercase processing
if (upper[i] % 2 == 0) {
count += upper[i];
} else {
count += upper[i] - 1; // Take even portion
isOddPresent = true; // Mark that an odd element exists
}
}
// Step 4: Add 1 for the central odd element if any odd frequency was found
return count + (isOddPresent ? 1 : 0);
}
};
6. Problem 2: Sorting the Sentence — Problem Breakdown
Problem Statement
A sentence is a list of words separated by single spaces, where each word contains a 1-indexed integer (from 1 to 9) appended at its end. Reconstruct the sentence by placing each word at its correct 1-based position and removing the appended numerical indices and extra spaces.
Example
- Input String:
- Token Extraction:
"is2"Word:"is", Position:2"sentence4"Word:"sentence", Position:4"This1"Word:"This", Position:1"a3"Word:"a", Position:3
- Target Output:
"This is a sentence"
7. Token Parsing and Positional Bucket Placement Model
To reorder the words in time, we construct a vector of strings of size 10 (indices 0 through 9). Index 0 remains unused, while indices 1–9 directly represent sentence positions.
8. Crucial Edge Case: Boundary Processing for the Final Word
In a standard space-delimited string parsing loop, words are processed upon encountering a space character ' '.
Critical Pitfall: The final word of a sentence does not end with a space character
' '. When the iteration loop hitsindex == s.size(), the parsing loop terminates with the final word stranded inside thetempbuffer without being processed into theansbucket array.
Dual Solution Framework
9. Sorting the Sentence: Complete Implementation Strategy
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution {
public:
string sortSentence(string s) {
vector<string> ans(10); // Buckets 1 to 9
string temp = "";
int count = 0; // Tracks total number of words processed
int index = 0;
// Step 1: Parse the string token by token
while (index < s.size()) {
if (s[index] == ' ') {
// Extract 1-based index position from the last character
int pos = temp[temp.size() - 1] - '0';
temp.pop_back(); // Remove digit
ans[pos] = temp; // Place word in target bucket
temp.clear(); // Reset temporary buffer
count++;
} else {
temp += s[index];
}
index++;
}
// Step 2: Handle boundary condition for the final word (no trailing space)
int pos = temp[temp.size() - 1] - '0';
temp.pop_back();
ans[pos] = temp;
temp.clear();
count++;
// Step 3: Reconstruct final sentence from index buckets 1 to count
string result = "";
for (int i = 1; i <= count; i++) {
result += ans[i];
result += " "; // Add inter-word spacing
}
// Step 4: Strip the trailing whitespace from the final word
result.pop_back();
return result;
}
};
10. Comparative Complexity & Strategy Analysis
Summary and Key Takeaways
- Symmetrical Symmetry Logic: Palindromes rely on even character pairing. Any even frequency count contributes fully; odd frequency counts contribute .
- Center Pivot Guarantee: At most one odd-frequency character can be assigned to the central position of a palindrome string.
- Fixed Frequency Mapping: Utilizing -element vectors mapped via ASCII offsets (
ch - 'a'orch - 'A') offers optimal auxiliary space overhead compared to general-purpose hash maps. - Direct Index Placement: When positions are bounded in a small integer range (e.g., –), a bucket array allows immediate positional placement without needing dynamic sorting routines like
std::sort. - String Parsing Boundaries: Always account for missing trailing delimiters when parsing delimited strings in a loop. Handled either by appending pre-padding or executing post-loop cleanup.
- Output Sanitation: Dynamic sentence construction using inter-word spacers inevitably leaves a trailing delimiter. Use
result.pop_back()to cleanly trim trailing whitespace.