Hard

题目描述

给定一个只包含 0 和 1 的数组 arr,将数组分成三个非空部分,使得所有这些部分表示相同的二进制值。

如果可以做到,请返回任何 [i, j],其中 i + 1 < j,使得:

  • arr[0], arr[1], ..., arr[i] 是第一部分
  • arr[i + 1], arr[i + 2], ..., arr[j - 1] 是第二部分
  • arr[j], arr[j + 1], ..., arr[arr.length - 1] 是第三部分
  • 所有三个部分具有相等的二进制值

如果无法做到,请返回 [-1, -1]

注意,在考虑它所表示的二进制值时,会使用整个部分。例如,[1,1,0] 在十进制中表示 6,而不是 3。此外,允许前导零,所以 [0,1,1][1,1] 表示相同的值。

示例 1:

输入: arr = [1,0,1,0,1]
输出: [0,3]

示例 2:

输入: arr = [1,1,0,1,1]  
输出: [-1,-1]

示例 3:

输入: arr = [1,0,1,0,0,1]
输出: [0,2]

提示:

  • 3 <= arr.length <= 3 * 10^4
  • arr[i] 是 0 或 1

解题思路

这道题要求将数组分成三个相等的二进制数部分。关键思路如下:

核心观察

  1. 1的个数必须能被3整除:如果总共有 count 个1,且 count % 3 != 0,则无解
  2. 特殊情况:如果 count == 0(全为0),任何分割都可以,返回 [0, 2]
  3. 每部分必须有 count/3 个1:这是三个部分相等的必要条件

解法步骤

  1. 统计1的总数,检查是否能被3整除
  2. 找到每部分的第一个1和最后一个1的位置
  3. 从最后一部分开始比较,因为它决定了尾随0的数量
  4. 依次比较三个部分是否完全相同(包括0的分布)

实现要点

  • 先找到第三部分第一个1的位置,以此为基准
  • 逐位比较三个部分,确保每一位都相等
  • 返回合适的分割点 [i, j],其中 i 是第一部分结束位置,j 是第三部分开始位置

时间复杂度O(n),空间复杂度O(1),是最优解法。

代码实现

class Solution {
public:
    vector<int> threeEqualParts(vector<int>& arr) {
        int n = arr.size();
        int count = 0;
        
        // 统计1的个数
        for (int x : arr) {
            count += x;
        }
        
        // 如果1的个数不能被3整除,返回无解
        if (count % 3 != 0) {
            return {-1, -1};
        }
        
        // 如果没有1,任意分割都可以
        if (count == 0) {
            return {0, 2};
        }
        
        int target = count / 3;
        
        // 找到第一部分、第二部分、第三部分的第一个1的位置
        int first = -1, second = -1, third = -1;
        int ones = 0;
        
        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                ones++;
                if (ones == 1) first = i;
                else if (ones == target + 1) second = i;
                else if (ones == 2 * target + 1) third = i;
            }
        }
        
        // 从第三部分开始比较,确保三部分相等
        while (third < n && arr[first] == arr[second] && arr[second] == arr[third]) {
            first++;
            second++;
            third++;
        }
        
        if (third == n) {
            return {first - 1, second};
        }
        
        return {-1, -1};
    }
};
class Solution:
    def threeEqualParts(self, arr: List[int]) -> List[int]:
        n = len(arr)
        count = sum(arr)
        
        # 如果1的个数不能被3整除,返回无解
        if count % 3 != 0:
            return [-1, -1]
        
        # 如果没有1,任意分割都可以
        if count == 0:
            return [0, 2]
        
        target = count // 3
        
        # 找到第一部分、第二部分、第三部分的第一个1的位置
        first = second = third = -1
        ones = 0
        
        for i in range(n):
            if arr[i] == 1:
                ones += 1
                if ones == 1:
                    first = i
                elif ones == target + 1:
                    second = i
                elif ones == 2 * target + 1:
                    third = i
        
        # 从第三部分开始比较,确保三部分相等
        while third < n and arr[first] == arr[second] == arr[third]:
            first += 1
            second += 1
            third += 1
        
        if third == n:
            return [first - 1, second]
        
        return [-1, -1]
public class Solution {
    public int[] ThreeEqualParts(int[] arr) {
        int n = arr.Length;
        int count = 0;
        
        // 统计1的个数
        foreach (int x in arr) {
            count += x;
        }
        
        // 如果1的个数不能被3整除,返回无解
        if (count % 3 != 0) {
            return new int[] {-1, -1};
        }
        
        // 如果没有1,任意分割都可以
        if (count == 0) {
            return new int[] {0, 2};
        }
        
        int target = count / 3;
        
        // 找到第一部分、第二部分、第三部分的第一个1的位置
        int first = -1, second = -1, third = -1;
        int ones = 0;
        
        for (int i = 0; i < n; i++) {
            if (arr[i] == 1) {
                ones++;
                if (ones == 1) first = i;
                else if (ones == target + 1) second = i;
                else if (ones == 2 * target + 1) third = i;
            }
        }
        
        // 从第三部分开始比较,确保三部分相等
        while (third < n && arr[first] == arr[second] && arr[second] == arr[third]) {
            first++;
            second++;
            third++;
        }
        
        if (third == n) {
            return new int[] {first - 1, second};
        }
        
        return new int[] {-1, -1};
    }
}
var threeEqualParts = function(arr) {
    const n = arr.length;
    const ones = arr.reduce((sum, val) => sum + val, 0);
    
    if (ones === 0) {
        return [0, 2];
    }
    
    if (ones % 3 !== 0) {
        return [-1, -1];
    }
    
    const onesPerPart = ones / 3;
    
    // Find positions of ones
    const onePositions = [];
    for (let i = 0; i < n; i++) {
        if (arr[i] === 1) {
            onePositions.push(i);
        }
    }
    
    // Find the start of each part (first 1 in each part)
    const start1 = onePositions[0];
    const start2 = onePositions[onesPerPart];
    const start3 = onePositions[2 * onesPerPart];
    
    // Check if the three parts have the same pattern of 1s and 0s
    while (start3 < n && arr[start1] === arr[start2] && arr[start2] === arr[start3]) {
        start1++;
        start2++;
        start3++;
    }
    
    if (start3 === n) {
        return [start1 - 1, start2];
    }
    
    return [-1, -1];
};

复杂度分析

复杂度类型复杂度
时间复杂度O(n)
空间复杂度O(1)