Minimum Number of Operations to Make Word K-Periodic
Problem
You are given a string word of size n, and an integer k such that k
divides n.
In one operation, you can pick any two indices i and j, that are divisible by k, then replace the substring of length k starting at i with the substring of length k starting at j. That is, replace the substring
word[i..i + k - 1] with the substring word[j..j + k - 1].
Return theminimum number of operations required to make word
k-periodic.
We say that word is k-periodic if there is some string s of length k
such that word can be obtained by concatenating s an arbitrary number of times. For example, if word == "ababab", then word is 2-periodic for s = "ab".
Examples
Example 1
Input: word = "leetcodeleet", k = 4
Output: 1
Explanation:
We can obtain a 4-periodic string by picking i = 4 and j = 0. After this
operation, word becomes equal to "leetleetleet".
Example 2
Input: word = "leetcoleet", k = 2
Output: 3
Explanation:
We can obtain a 2-periodic string by applying the operations in the table
below.
i | j | word
---|---|---
0 | 2 | etetcoleet
4 | 0 | etetetleet
6 | 0 | etetetetet
Constraints
1 <= n == word.length <= 10^51 <= k <= word.lengthkdividesword.length.wordconsists only of lowercase English letters.
Solution
Method 1 – Greedy Counting of k-Substrings
Intuition
To make the word k-periodic, all k-length blocks must be the same. We can count the frequency of each k-length substring and find the most common one. The minimum operations is the number of blocks minus the count of the most common block.
Approach
- Split the word into n // k blocks of length k.
- Count the frequency of each block.
- The answer is total blocks minus the frequency of the most common block.
Code
C++
#include <string>
#include <unordered_map>
using namespace std;
class Solution {
public:
int minimumOperations(string word, int k) {
int n = word.size(), blocks = n / k;
unordered_map<string, int> freq;
for (int i = 0; i < n; i += k)
freq[word.substr(i, k)]++;
int maxf = 0;
for (auto& [s, f] : freq) maxf = max(maxf, f);
return blocks - maxf;
}
};
Go
func minimumOperations(word string, k int) int {
n := len(word)
blocks := n / k
freq := map[string]int{}
for i := 0; i < n; i += k {
freq[word[i:i+k]]++
}
maxf := 0
for _, f := range freq {
if f > maxf {
maxf = f
}
}
return blocks - maxf
}
Java
import java.util.*;
class Solution {
public int minimumOperations(String word, int k) {
int n = word.length(), blocks = n / k;
Map<String, Integer> freq = new HashMap<>();
for (int i = 0; i < n; i += k)
freq.put(word.substring(i, i + k), freq.getOrDefault(word.substring(i, i + k), 0) + 1);
int maxf = 0;
for (int f : freq.values()) maxf = Math.max(maxf, f);
return blocks - maxf;
}
}
Kotlin
class Solution {
fun minimumOperations(word: String, k: Int): Int {
val n = word.length; val blocks = n / k
val freq = mutableMapOf<String, Int>()
for (i in 0 until n step k) {
val sub = word.substring(i, i + k)
freq[sub] = freq.getOrDefault(sub, 0) + 1
}
val maxf = freq.values.maxOrNull() ?: 0
return blocks - maxf
}
}
Python
class Solution:
def minimumOperations(self, word: str, k: int) -> int:
n = len(word)
blocks = n // k
from collections import Counter
freq = Counter(word[i:i+k] for i in range(0, n, k))
return blocks - max(freq.values())
Rust
use std::collections::HashMap;
impl Solution {
pub fn minimum_operations(word: String, k: i32) -> i32 {
let n = word.len();
let k = k as usize;
let blocks = n / k;
let mut freq = HashMap::new();
let w = word.as_bytes();
for i in (0..n).step_by(k) {
let sub = &w[i..i + k];
*freq.entry(sub).or_insert(0) += 1;
}
let maxf = freq.values().max().copied().unwrap_or(0);
(blocks as i32) - maxf
}
}
TypeScript
class Solution {
minimumOperations(word: string, k: number): number {
const n = word.length, blocks = n / k;
const freq = new Map<string, number>();
for (let i = 0; i < n; i += k) {
const sub = word.slice(i, i + k);
freq.set(sub, (freq.get(sub) ?? 0) + 1);
}
let maxf = 0;
for (const f of freq.values()) maxf = Math.max(maxf, f);
return blocks - maxf;
}
}
Complexity
- ⏰ Time complexity:
O(n)— n = length of word, single pass. - 🧺 Space complexity:
O(n // k)— for substring frequency map.