Count Beautiful Splits in an Array
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given an array nums.
A split of an array nums is beautiful if:
- The array
numsis split into three subarrays:nums1,nums2, andnums3, such thatnumscan be formed by concatenatingnums1,nums2, andnums3in that order. - The subarray
nums1is a prefix ofnums2ORnums2is a prefix ofnums3.
Return the number of ways you can make this split.
Examples
Example 1
Input: nums = [1,1,2,1]
Output: 2
Explanation:
The beautiful splits are:
1. A split with `nums1 = [1]`, `nums2 = [1,2]`, `nums3 = [1]`.
2. A split with `nums1 = [1]`, `nums2 = [1]`, `nums3 = [2,1]`.
Example 2
Input: nums = [1,2,3,4]
Output: 0
Explanation:
There are 0 beautiful splits.
Constraints
1 <= nums.length <= 50000 <= nums[i] <= 50
Solution
Method 1 – Prefix and Suffix Hashing 1
Intuition
To efficiently check if one subarray is a prefix of another, we can use rolling hash or tuple comparison. For each possible split, we check if nums1 is a prefix of nums2 or nums2 is a prefix of nums3. We iterate over all possible splits and count the valid ones.
Approach
- Iterate over all possible split points (i, j) such that 1 ≤ i < j < n.
- For each split:
- nums1 = nums[0:i], nums2 = nums[i:j], nums3 = nums[j:n].
- Check if nums1 is a prefix of nums2 (i ≤ j-i and nums1 == nums2[0:i]).
- Check if nums2 is a prefix of nums3 (j-i ≤ n-j and nums2 == nums3[0:j-i]).
- Count the number of splits where either condition is true.
- Return the count.
Code
C++
class Solution {
public:
int countBeautifulSplits(vector<int>& nums) {
int n = nums.size(), ans = 0;
for (int i = 1; i < n-1; ++i) {
for (int j = i+1; j < n; ++j) {
int len1 = i, len2 = j-i, len3 = n-j;
bool cond1 = len1 <= len2 && equal(nums.begin(), nums.begin()+len1, nums.begin()+i);
bool cond2 = len2 <= len3 && equal(nums.begin()+i, nums.begin()+j, nums.begin()+j);
if (cond1 || cond2) ans++;
}
}
return ans;
}
};
Go
func countBeautifulSplits(nums []int) int {
n, ans := len(nums), 0
for i := 1; i < n-1; i++ {
for j := i+1; j < n; j++ {
len1, len2, len3 := i, j-i, n-j
cond1 := len1 <= len2 && slices.Equal(nums[:len1], nums[i:j][:len1])
cond2 := len2 <= len3 && slices.Equal(nums[i:j], nums[j:][:len2])
if cond1 || cond2 {
ans++
}
}
}
return ans
}
Java
class Solution {
public int countBeautifulSplits(int[] nums) {
int n = nums.length, ans = 0;
for (int i = 1; i < n-1; ++i) {
for (int j = i+1; j < n; ++j) {
int len1 = i, len2 = j-i, len3 = n-j;
boolean cond1 = len1 <= len2 && Arrays.equals(Arrays.copyOfRange(nums, 0, len1), Arrays.copyOfRange(nums, i, i+len1));
boolean cond2 = len2 <= len3 && Arrays.equals(Arrays.copyOfRange(nums, i, j), Arrays.copyOfRange(nums, j, j+len2));
if (cond1 || cond2) ans++;
}
}
return ans;
}
}
Kotlin
class Solution {
fun countBeautifulSplits(nums: IntArray): Int {
val n = nums.size
var ans = 0
for (i in 1 until n-1) {
for (j in i+1 until n) {
val len1 = i
val len2 = j-i
val len3 = n-j
val cond1 = len1 <= len2 && nums.slice(0 until len1) == nums.slice(i until i+len1)
val cond2 = len2 <= len3 && nums.slice(i until j) == nums.slice(j until j+len2)
if (cond1 || cond2) ans++
}
}
return ans
}
}
Python
class Solution:
def countBeautifulSplits(self, nums: list[int]) -> int:
n = len(nums)
ans = 0
for i in range(1, n-1):
for j in range(i+1, n):
len1 = i
len2 = j-i
len3 = n-j
cond1 = len1 <= len2 and nums[:len1] == nums[i:i+len1]
cond2 = len2 <= len3 and nums[i:j] == nums[j:j+len2]
if cond1 or cond2:
ans += 1
return ans
Rust
impl Solution {
pub fn count_beautiful_splits(nums: Vec<i32>) -> i32 {
let n = nums.len();
let mut ans = 0;
for i in 1..n-1 {
for j in i+1..n {
let len1 = i;
let len2 = j-i;
let len3 = n-j;
let cond1 = len1 <= len2 && nums[..len1] == nums[i..i+len1];
let cond2 = len2 <= len3 && nums[i..j] == nums[j..j+len2];
if cond1 || cond2 {
ans += 1;
}
}
}
ans
}
}
TypeScript
class Solution {
countBeautifulSplits(nums: number[]): number {
const n = nums.length;
let ans = 0;
for (let i = 1; i < n-1; ++i) {
for (let j = i+1; j < n; ++j) {
const len1 = i, len2 = j-i, len3 = n-j;
const cond1 = len1 <= len2 && nums.slice(0, len1).join(',') === nums.slice(i, i+len1).join(',');
const cond2 = len2 <= len3 && nums.slice(i, j).join(',') === nums.slice(j, j+len2).join(',');
if (cond1 || cond2) ans++;
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n^2 * m), where n is the length of nums and m is the maximum subarray length compared. - 🧺 Space complexity:
O(1), ignoring input and output storage.