|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[927. 三等分](https://leetcode.cn/problems/three-equal-parts/solution/by-ac_oier-9i2s/)** ,难度为 **困难**。 |
| 4 | + |
| 5 | +Tag : 「模拟」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +给定一个由 `0` 和 `1` 组成的数组 `arr`,将数组分成 `3` 个非空的部分 ,使得所有这些部分表示相同的二进制值。 |
| 10 | + |
| 11 | +如果可以做到,请返回任何 `[i, j]`,其中 `i+1 < j`,这样一来: |
| 12 | + |
| 13 | +* `arr[0], arr[1], ..., arr[i]` 为第一部分; |
| 14 | +* `arr[i + 1], arr[i + 2], ..., arr[j - 1]` 为第二部分; |
| 15 | +* `arr[j], arr[j + 1], ..., arr[arr.length - 1]` 为第三部分。 |
| 16 | +* 这三个部分所表示的二进制值相等。 |
| 17 | + |
| 18 | +如果无法做到,就返回 `[-1, -1]`。 |
| 19 | + |
| 20 | +注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体。例如,`[1,1,0]` 表示十进制中的 `6`,而不会是 `3`。此外,前导零也是被允许的,所以 `[0,1,1]` 和 `[1,1]` 表示相同的值。 |
| 21 | + |
| 22 | +示例 1: |
| 23 | +``` |
| 24 | +输入:arr = [1,0,1,0,1] |
| 25 | +
|
| 26 | +输出:[0,3] |
| 27 | +``` |
| 28 | +示例 2: |
| 29 | +``` |
| 30 | +输入:arr = [1,1,0,1,1] |
| 31 | +
|
| 32 | +输出:[-1,-1] |
| 33 | +``` |
| 34 | +示例 3: |
| 35 | +``` |
| 36 | +输入:arr = [1,1,0,0,1] |
| 37 | +
|
| 38 | +输出:[0,2] |
| 39 | +``` |
| 40 | + |
| 41 | +提示: |
| 42 | +* $3 <= arr.length <= 3 \times 10^4$ |
| 43 | +* `arr[i]` 是 `0` 或 `1` |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +### 模拟 |
| 48 | + |
| 49 | +心情不好,写的代码也不好。 |
| 50 | + |
| 51 | +就大概讲讲啥意思吧: |
| 52 | + |
| 53 | +1. 先统计 `1` 的个数 `cnt`,若 `cnt = 0` 代表能够任意划分,直接返回 `[0, 2]`; |
| 54 | +2. 若 `cnt` 不为 $3$ 的倍数,必然不能正常划分,返回无解 `[-1, -1]`,否则可知三段中必然每一段 `1` 的数量均为 $t = \frac{cnt}{3}$ 个; |
| 55 | +3. 最后检查「三段中 `1` 的间隔位是否相同,后缀 `0` 个数是否相同」即可: |
| 56 | + 1. 创建二维数组 `ins` 记录三段中,相邻 `1` 之间的间隔情况,若存在间隔 `1` 不同,返回无解 `[-1, -1]`; |
| 57 | + 2. 预处理四个变量 `l1`、`l2`、`r1` 和 `r2`,分别代表能够划分出最左边 `t` 个 `1` 的左右端点,以及能够划分出最右边 `t` 个 `1` 的左右端点,同时统计最后一段的后缀 `0` 的数量 `d`,配合四个变量来检查能否划分出具有 `d` 个后缀 `0` 的前两段。 |
| 58 | + |
| 59 | +代码: |
| 60 | +```Java |
| 61 | +class Solution { |
| 62 | + public int[] threeEqualParts(int[] arr) { |
| 63 | + int[] fail = new int[]{-1, -1}; |
| 64 | + // 检查总数 |
| 65 | + int n = arr.length, cnt = 0; |
| 66 | + for (int i = 0; i < n; i++) cnt += arr[i]; |
| 67 | + if (cnt == 0) return new int[]{0, 2}; |
| 68 | + if (cnt % 3 != 0) return fail; |
| 69 | + // 检查间隔相对位 |
| 70 | + int t = cnt / 3; |
| 71 | + int[][] ins = new int[3][t]; |
| 72 | + for (int i = 0, j = -1, k = 0, p = 0, idx = 0; i < n; i++) { |
| 73 | + if (arr[i] == 0) continue; |
| 74 | + if (j != -1) ins[p][idx++] = i - j; |
| 75 | + if (++k == t) { |
| 76 | + j = -1; k = 0; p++; idx = 0; |
| 77 | + } else { |
| 78 | + j = i; |
| 79 | + } |
| 80 | + } |
| 81 | + for (int i = 0; i < t; i++) { |
| 82 | + if (ins[0][i] == ins[1][i] && ins[0][i] == ins[2][i] && ins[1][i] == ins[2][i]) continue; |
| 83 | + return fail; |
| 84 | + } |
| 85 | + // 构造答案(l1 和 l2 分别为能够划分出最左边 t 个 1 的 左右端点;r1 和 r2 分别为能够划分出最右边 t 个 1 的左右端点) |
| 86 | + int l1 = -1, l2 = -1, r1 = -1, r2 = -1; |
| 87 | + for (int i = 0, k = 0; i < n; i++) { |
| 88 | + k += arr[i]; |
| 89 | + if (k == t) { |
| 90 | + if (l1 == -1) l1 = i; |
| 91 | + } else if (k == t + 1) { |
| 92 | + l2 = i - 1; |
| 93 | + break; |
| 94 | + } |
| 95 | + } |
| 96 | + for (int i = n - 1, k = 0; i >= 0; i--) { |
| 97 | + k += arr[i]; |
| 98 | + if (k == t) { |
| 99 | + if (r2 == -1) r2 = i; |
| 100 | + } else if (k == t + 1) { |
| 101 | + r1 = i + 1; |
| 102 | + break; |
| 103 | + } |
| 104 | + } |
| 105 | + int d = 0; // d 为最右边一段的后缀 0 的数量 |
| 106 | + for (int i = n - 1; i >= 0; i--) { |
| 107 | + if (arr[i] == 1) break; |
| 108 | + d++; |
| 109 | + } |
| 110 | + if (l1 + d > l2 || r1 + d > r2) return fail; |
| 111 | + return new int[]{l1 + d, r1 + d}; |
| 112 | + } |
| 113 | +} |
| 114 | +``` |
| 115 | +* 时间复杂度:$O(n)$ |
| 116 | +* 空间复杂度:$O(n)$ |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +### 最后 |
| 121 | + |
| 122 | +这是我们「刷穿 LeetCode」系列文章的第 `No.927` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 123 | + |
| 124 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 125 | + |
| 126 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 127 | + |
| 128 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 129 | + |
0 commit comments