Facebook Pixel

3271. Hash Divided String

MediumStringSimulation
LeetCode ↗

Problem Description

You are given a string s of length n and an integer k, where n is a multiple of k. Your goal is to transform the string s into a new compressed string called result that has a length of n / k.

The transformation process works as follows:

  1. Divide the string: Split s into n / k consecutive substrings, where each substring has exactly k characters.

  2. Process each substring: For each substring (processing them in order from left to right):

    • Calculate the hash value of each character, where the hash value is the character's position in the alphabet ('a' → 0, 'b' → 1, 'c' → 2, ..., 'z' → 25)
    • Sum up all the hash values of the characters in the current substring
    • Take the remainder when this sum is divided by 26 (this gives you hashedChar)
    • Convert hashedChar back to a lowercase letter (0 → 'a', 1 → 'b', ..., 25 → 'z')
    • Append this character to the result string
  3. Return the result: After processing all substrings, return the final result string.

For example, if s = "abcd" and k = 2:

  • First substring: "ab" → hash values: 0 + 1 = 1 → 1 % 26 = 1 → 'b'
  • Second substring: "cd" → hash values: 2 + 3 = 5 → 5 % 26 = 5 → 'f'
  • Result: "bf"

The solution iterates through the string in chunks of size k, computes the sum of character positions for each chunk, takes modulo 26, and converts back to a character to build the final result.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Simulation / Basic DSA?

This problem maps to Simulation / Basic DSA through a short path in the full flowchart.

Parsesymbols?noDirectsimulation?yesSimulation /Basic DSA

Hash Divided String follows the described steps directly with careful simulation.

Open in Flowchart

Intuition

The problem is essentially asking us to create a hash function that compresses a string by mapping every k characters to a single character. This is a straightforward simulation problem where we need to follow the given instructions step by step.

The key insight is recognizing that this is a chunking and hashing operation:

  • We're dividing the input into equal-sized chunks
  • Each chunk gets reduced to a single character through a hashing process
  • The hash function is simply the sum of character positions modulo 26

Why does this approach make sense?

  1. Fixed chunk size: Since n is guaranteed to be a multiple of k, we know we can cleanly divide the string into chunks of size k without any remainder. This makes the iteration pattern simple - we can jump by k positions each time.

  2. Character mapping: The problem defines a clear mapping from characters to numbers ('a' → 0, 'b' → 1, etc.). This is just ord(char) - ord('a'), which gives us the alphabetical position.

  3. Modulo operation: Taking the sum modulo 26 ensures our result always maps back to a valid lowercase letter (since there are 26 letters in the alphabet). No matter how large the sum gets, sum % 26 will always be in the range [0, 25].

  4. Reverse mapping: Converting back from a number to a character is the inverse operation: chr(ord('a') + hashedChar).

The solution naturally flows from these observations - we iterate through the string in steps of k, calculate the hash for each substring, and build our result character by character. There's no need for complex data structures or algorithms; it's purely a matter of following the hashing recipe provided in the problem statement.

Solution Approach

The solution implements a direct simulation of the hashing process described in the problem. Let's walk through the implementation step by step:

1. Initialize the result container:

ans = []

We use a list to collect the hashed characters, which will be joined into a string at the end. This is more efficient than string concatenation in Python.

2. Iterate through the string in chunks of size k:

for i in range(0, len(s), k):

The loop starts at index 0 and jumps by k positions each iteration. This ensures we process each substring of length k exactly once. For example, if len(s) = 6 and k = 2, we'll have i values of 0, 2, and 4.

3. Calculate the hash sum for each substring:

t = 0
for j in range(i, i + k):
    t += ord(s[j]) - ord("a")

For each substring starting at position i:

  • We iterate through the next k characters (from index i to i + k - 1)
  • Convert each character to its hash value using ord(s[j]) - ord("a")
    • ord("a") gives 97, ord("b") gives 98, etc.
    • Subtracting ord("a") normalizes these to 0, 1, 2, ... 25
  • Accumulate the sum in variable t

4. Apply modulo and convert to character:

hashedChar = t % 26
ans.append(chr(ord("a") + hashedChar))
  • Take the sum modulo 26 to get a value in range [0, 25]
  • Convert this number back to a character:
    • ord("a") gives the ASCII value of 'a' (97)
    • Adding hashedChar gives us the ASCII value of our target character
    • chr() converts the ASCII value back to a character
  • Append the resulting character to our answer list

5. Build and return the final string:

return "".join(ans)

Join all the hashed characters into a single string and return it.

Time Complexity: O(n) where n is the length of the input string, as we visit each character exactly once.

Space Complexity: O(n/k) for storing the result string, which has length n/k.

The algorithm is straightforward - no complex data structures or advanced techniques are needed. It's a pure simulation that follows the problem's hashing recipe exactly as specified.

Example Walkthrough

Let's walk through the solution with a concrete example: s = "mauigqpe" and k = 4.

Step 1: Divide into chunks

  • String length: 8 characters
  • Number of chunks: 8 / 4 = 2 chunks
  • Chunks: "maui" and "gqpe"

Step 2: Process first chunk "maui"

  • Calculate hash values:
    • 'm' → 12 (m is the 13th letter, so position 12)
    • 'a' → 0
    • 'u' → 20
    • 'i' → 8
  • Sum: 12 + 0 + 20 + 8 = 40
  • Apply modulo: 40 % 26 = 14
  • Convert to character: 14 → 'o' (since 'a' + 14 = 'o')

Step 3: Process second chunk "gqpe"

  • Calculate hash values:
    • 'g' → 6
    • 'q' → 16
    • 'p' → 15
    • 'e' → 4
  • Sum: 6 + 16 + 15 + 4 = 41
  • Apply modulo: 41 % 26 = 15
  • Convert to character: 15 → 'p' (since 'a' + 15 = 'p')

Step 4: Build result

  • First chunk produced: 'o'
  • Second chunk produced: 'p'
  • Final result: "op"

The algorithm compressed the 8-character string "mauigqpe" into a 2-character string "op" by hashing every 4 consecutive characters into a single character.

Solution Implementation

1class Solution:
2    def stringHash(self, s: str, k: int) -> str:
3        """
4        Hashes a string by dividing it into substrings of length k and converting each substring
5        to a single character based on the sum of character positions modulo 26.
6      
7        Args:
8            s: Input string to be hashed
9            k: Length of each substring
10          
11        Returns:
12            Hashed string where each k characters are reduced to a single character
13        """
14        result = []
15      
16        # Process the string in chunks of size k
17        for i in range(0, len(s), k):
18            # Calculate sum of character positions for current substring
19            substring_sum = 0
20          
21            # Sum up the positions (0-indexed) of each character in the current chunk
22            for j in range(i, i + k):
23                # Convert character to its position (a=0, b=1, ..., z=25)
24                substring_sum += ord(s[j]) - ord('a')
25          
26            # Apply modulo 26 to get the hashed character position
27            hashed_position = substring_sum % 26
28          
29            # Convert position back to character and add to result
30            hashed_character = chr(ord('a') + hashed_position)
31            result.append(hashed_character)
32      
33        # Join all hashed characters into final string
34        return ''.join(result)
35
1class Solution {
2    /**
3     * Hashes a string by dividing it into substrings of length k and 
4     * converting each substring into a single character.
5     * 
6     * @param s The input string to be hashed
7     * @param k The length of each substring
8     * @return The hashed string
9     */
10    public String stringHash(String s, int k) {
11        // StringBuilder to store the resulting hashed string
12        StringBuilder result = new StringBuilder();
13      
14        // Get the length of the input string
15        int stringLength = s.length();
16      
17        // Process the string in chunks of size k
18        for (int startIndex = 0; startIndex < stringLength; startIndex += k) {
19            // Initialize sum for current substring
20            int charSum = 0;
21          
22            // Calculate the sum of character values in the current substring
23            // Each character's value is its position in the alphabet (a=0, b=1, etc.)
24            for (int currentIndex = startIndex; currentIndex < startIndex + k; currentIndex++) {
25                charSum += s.charAt(currentIndex) - 'a';
26            }
27          
28            // Hash the sum by taking modulo 26 to get a value between 0-25
29            int hashedValue = charSum % 26;
30          
31            // Convert the hashed value back to a character and append to result
32            // Add the hashed value to 'a' to get the corresponding character
33            result.append((char) ('a' + hashedValue));
34        }
35      
36        // Return the final hashed string
37        return result.toString();
38    }
39}
40
1class Solution {
2public:
3    string stringHash(string s, int k) {
4        string result;
5        int stringLength = s.length();
6      
7        // Process the string in chunks of size k
8        for (int startIndex = 0; startIndex < stringLength; startIndex += k) {
9            int sum = 0;
10          
11            // Calculate sum of character values in current chunk
12            // Each character's value is its position in alphabet (a=0, b=1, ..., z=25)
13            for (int currentIndex = startIndex; currentIndex < startIndex + k; ++currentIndex) {
14                sum += s[currentIndex] - 'a';
15            }
16          
17            // Hash the sum by taking modulo 26 to get a value between 0-25
18            int hashedValue = sum % 26;
19          
20            // Convert the hashed value back to a character and append to result
21            result += static_cast<char>('a' + hashedValue);
22        }
23      
24        return result;
25    }
26};
27
1/**
2 * Hashes a string by dividing it into segments of length k and converting each segment
3 * @param s - The input string to be hashed (assumed to contain only lowercase letters)
4 * @param k - The length of each segment to process
5 * @returns The hashed string result
6 */
7function stringHash(s: string, k: number): string {
8    // Array to store the hashed characters
9    const hashedCharacters: string[] = [];
10  
11    // Get the total length of the input string
12    const stringLength: number = s.length;
13
14    // Process the string in segments of length k
15    for (let startIndex = 0; startIndex < stringLength; startIndex += k) {
16        // Initialize sum for current segment
17        let segmentSum: number = 0;
18      
19        // Calculate the sum of character values in the current segment
20        // Each character's value is its position in the alphabet (a=0, b=1, ..., z=25)
21        for (let currentIndex = startIndex; currentIndex < startIndex + k; currentIndex++) {
22            segmentSum += s.charCodeAt(currentIndex) - 97; // 97 is ASCII code for 'a'
23        }
24      
25        // Hash the sum by taking modulo 26 to get a value between 0-25
26        const hashedValue: number = segmentSum % 26;
27      
28        // Convert the hashed value back to a lowercase letter and add to result
29        hashedCharacters.push(String.fromCharCode(97 + hashedValue));
30    }
31
32    // Join all hashed characters into a single string
33    return hashedCharacters.join('');
34}
35

Time and Space Complexity

The time complexity is O(n), where n is the length of the string s. The algorithm iterates through the string in chunks of size k, processing n/k chunks total. For each chunk, it performs k character operations (converting to ASCII values and summing). Therefore, the total operations are (n/k) * k = n, resulting in linear time complexity.

The space complexity is O(n/k) for the answer list that stores the hashed characters. Since each chunk of k characters produces one hashed character, the answer list contains n/k elements. If we ignore the space consumption of the answer string (as mentioned in the reference), the space complexity would be O(1) as we only use a constant amount of extra space for variables t, i, and j.

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Off-by-One Errors in Character Position Calculation

A common mistake is incorrectly calculating the character's position in the alphabet. Developers might forget to subtract ord('a') or might use 1-based indexing instead of 0-based.

Incorrect Implementation:

# Wrong: Using 1-based indexing
substring_sum += ord(s[j]) - ord('a') + 1  # 'a' would be 1, not 0

# Wrong: Forgetting to normalize
substring_sum += ord(s[j])  # Would give ASCII values like 97, 98, etc.

Solution: Always remember that the problem specifies 0-based positions ('a' → 0), so use ord(s[j]) - ord('a') consistently.

2. Integer Overflow in Languages with Fixed Integer Sizes

While Python handles arbitrary precision integers automatically, in languages like Java or C++, accumulating large sums might cause integer overflow if the substring is very long or contains many 'z' characters.

Potential Issue in Other Languages:

// In Java, this could overflow for large k values
int sum = 0;
for (int j = i; j < i + k; j++) {
    sum += s.charAt(j) - 'a';  // Could overflow if k is very large
}

Solution: Apply modulo 26 during accumulation to prevent overflow:

substring_sum = 0
for j in range(i, i + k):
    substring_sum = (substring_sum + ord(s[j]) - ord('a')) % 26

3. Incorrect Loop Boundaries

Developers might incorrectly set up the inner loop boundaries, especially when dealing with the end index.

Incorrect Implementation:

# Wrong: Off by one - would include k+1 characters
for j in range(i, i + k + 1):
    substring_sum += ord(s[j]) - ord('a')

# Wrong: Would miss the last character
for j in range(i, i + k - 1):
    substring_sum += ord(s[j]) - ord('a')

Solution: Use range(i, i + k) which correctly iterates from index i to i + k - 1, giving exactly k characters.

4. String Concatenation Performance

Using string concatenation in a loop can be inefficient in Python due to string immutability.

Inefficient Implementation:

result = ""
for i in range(0, len(s), k):
    # ... calculate hashed_character
    result += hashed_character  # Creates a new string object each time

Solution: Use a list to collect characters and join at the end:

result = []
for i in range(0, len(s), k):
    # ... calculate hashed_character
    result.append(hashed_character)
return ''.join(result)

5. Assuming Input Validity

The problem states that n is a multiple of k, but in production code, you might want to validate this assumption.

Defensive Programming:

def stringHash(self, s: str, k: int) -> str:
    if len(s) % k != 0:
        raise ValueError(f"String length {len(s)} is not divisible by k={k}")
  
    # Rest of the implementation...

6. Misunderstanding the Modulo Operation

Some developers might apply modulo 26 at the wrong step or forget it entirely.

Incorrect Implementation:

# Wrong: Applying modulo to each character individually
for j in range(i, i + k):
    substring_sum += (ord(s[j]) - ord('a')) % 26  # Unnecessary here

# Wrong: Forgetting modulo entirely
hashed_position = substring_sum  # Could be > 25, causing chr() to produce non-lowercase letters

Solution: Apply modulo 26 only once after summing all characters in the substring:

hashed_position = substring_sum % 26

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which type of traversal does breadth first search do?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More