leetcode
leetcode 851 ~ 900
三等分

三等分

难度:

标签:

题目描述

代码结果

运行时间: 50 ms, 内存: 17.7 MB


/*
 * Problem Statement:
 * Given an array arr of 0s and 1s, divide the array into 3 non-empty parts such that all of these parts represent the same binary value.
 * If possible, return any [i, j] with i + 1 < j, such that:
 * - arr[0], arr[1], ..., arr[i] is the first part;
 * - arr[i + 1], arr[i + 2], ..., arr[j - 1] is the second part;
 * - arr[j], arr[j + 1], ..., arr[arr.length - 1] is the third part.
 * These parts must represent the same binary value.
 * If it's not possible, return [-1, -1].
 *
 * Example:
 * Input: arr = [1,0,1,0,1]
 * Output: [0, 3]
 *
 * Approach:
 * 1. Count the total number of 1s in the array.
 * 2. If this number is not divisible by 3, return [-1, -1] since we cannot split them equally.
 * 3. Identify the positions of the 1s and attempt to divide them into three equal parts.
 * 4. Verify that the segments between these positions represent the same binary value.
 */

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Solution {
    public int[] threeEqualParts(int[] arr) {
        long countOnes = Arrays.stream(arr).filter(i -> i == 1).count();
        if (countOnes % 3 != 0) return new int[]{-1, -1};
        if (countOnes == 0) return new int[]{0, arr.length - 1};

        long k = countOnes / 3;
        List<Integer> positions = Arrays.stream(arr).boxed().collect(Collectors.toList());
        int first = positions.indexOf(1);
        int second = nthIndexOf(arr, 1, k + 1);
        int third = nthIndexOf(arr, 1, 2 * k + 1);

        while (third < arr.length && arr[first] == arr[second] && arr[second] == arr[third]) {
            first++;
            second++;
            third++;
        }

        if (third == arr.length) return new int[]{first - 1, second};
        return new int[]{-1, -1};
    }

    private int nthIndexOf(int[] arr, int value, long n) {
        int index = -1;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                n--;
                if (n == 0) {
                    index = i;
                    break;
                }
            }
        }
        return index;
    }
}

解释

方法:

该题解策略首先计算数组中1的总数。如果1的总数不能被3整除,直接返回[-1, -1]。如果整个数组都是0,返回[0, 2]。然后,将数组中1的位置存储在一个列表中,根据1的总数除以3的结果,确定三个部分中每一部分1的起始和结束位置。计算第三部分结束后剩余的0的数量,用这个信息来确定第一部分和第二部分的结束位置。最后,进行一次遍历来确认三部分的内容是否完全相同。如果相同,则返回第一部分和第三部分的结束位置作为结果;如果在任何点不相同,则返回[-1, -1]。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在你的算法中,如何保证每一部分的二进制值相等即使在存在前导零的情况下?
在算法中,通过确保每一部分中1的数量相等并且每一部分后面的0的数量也相等来保证每一部分的二进制值相等。首先,算法找到每一部分中1的起始和结束位置。接着,计算第三部分结束后剩余的0的数量,并将这些0分配到前两部分的末尾,确保每部分结束后的0的数量相同。最后,通过逐一比较三个部分从第一个1到最后一个0的内容,来确认它们是否完全相同。这样即使存在前导零,只要三部分内容完全一致,就能保证它们的二进制值相等。
🦆
为什么在计算1的总数不能被3整除时,就直接返回`[-1, -1]`,这里的逻辑基础是什么?
如果1的总数不能被3整除,那么无法将这些1均等地分配到三个部分中。每一部分必须含有相等数量的1,以确保三个部分的二进制值相等。如果1的总数不能整除3,至少有一个部分的1的数量将与其他部分不同,导致无法形成三个相等的部分。因此,如果1的总数不能被3整除,算法直接返回`[-1, -1]`表示无法分割成三个相等的部分。
🦆
在计算最后一部分后的0的数量时,为何这些0的数量对于第一部分和第二部分的结束位置有决定性影响?
最后一部分后的0的数量决定了我们可以在第一部分和第二部分后添加多少个0以保持三部分结构上的一致性。每部分的结束位置需要包括足够的0,使得三部分在1的分布和尾部0的数量上完全相同。因此,计算出第三部分后的0的数量后,我们可以确定第一部分和第二部分应当在哪里结束,即在对应部分的最后一个1之后再加上相同数量的0,以确保三个部分在二进制表示上完全相同。
🦆
当数组全为0时,返回`[0, 2]`的逻辑依据是什么?是否有其他可能的切分方法满足题目要求?
当数组全为0时,由于0的二进制值总是相等,因此可以任意切分数组为三个部分而保证它们的二进制值相同。返回`[0, 2]`是一种简单的切分方法,将前三个元素分为第一部分,其余为第二和第三部分。实际上,只要确保每部分至少有一个元素,任何切分方法都是有效的,例如`[0, 1]`或`[1, 2]`等都是可行的切分,满足题目要求。

相关问题