109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
package misc
|
||
|
||
import "testing"
|
||
|
||
// 题目(推测题干)
|
||
//
|
||
// 给定两个长度为 n 的 0/1 数组 a 和 b。
|
||
// 一次操作:选择 [L, R, V],满足 1 ≤ L ≤ R ≤ n,V ∈ {0,1},
|
||
// 将 a 中下标在 [L,R] 内的所有元素统一修改为 V(区间外不变)。
|
||
//
|
||
// 问:是否存在恰好一种操作使 a 变为 b?
|
||
// - 存在且唯一:输出该操作 [L,R,V](0-indexed 闭区间)
|
||
// - 不存在或不唯一:输出 -1
|
||
//
|
||
// 思路(0-indexed)
|
||
//
|
||
// 记 need = { i : a[i] != b[i] },即必须被改到的位置。
|
||
//
|
||
// 1. 找 lo = min(need), hi = max(need)。need 为空 → a == b,特判(见下)。
|
||
// 2. 区间 [L,R] 必须 ⊇ [lo, hi],否则 need 中落在区间外的位置不会被改。
|
||
// 3. 区间内每个位置改完都要等于 b;而一个操作只有一个 V,
|
||
// 所以 [lo,hi] 内 b 必须全相同,V = b[lo]。否则无解 (-1)。
|
||
// 4. L 的取值范围:L ≤ lo。向左能扩张到 b 中连续等于 V 的位置
|
||
// (这些位置改后仍等于 b,不破坏)。
|
||
// - L 唯一 ⟺ lo == 0(到左边界)或 b[lo-1] != V(左边紧邻不等于 V,无法扩张)
|
||
// 5. R 的取值范围:R ≥ hi。向右能扩张到 b 中连续等于 V 的位置。
|
||
// - R 唯一 ⟺ hi == n-1(到右边界)或 b[hi+1] != V
|
||
// 6. L、R 都唯一 → 输出 [lo, hi, V];否则 -1。
|
||
//
|
||
// 特判 a == b(need 为空):
|
||
// - 要一次操作让 a 不变:区间内 a 必须全等于 V。
|
||
// - 任何单点 [i,i] 配 V=a[i] 都可行。
|
||
// - n == 1:唯一解 [0, 0, a[0]]。
|
||
// - n >= 2:有多个单点选择 → 不唯一 → -1。
|
||
|
||
func uniqueRangeAssign(a, b []int) (L, R, V int, ok bool) {
|
||
n := len(a)
|
||
|
||
// 第 1 步:找 lo, hi
|
||
lo, hi := -1, -1
|
||
for i := 0; i < n; i++ {
|
||
if a[i] != b[i] {
|
||
if lo == -1 {
|
||
lo = i
|
||
}
|
||
hi = i
|
||
}
|
||
}
|
||
|
||
// 特判 a == b
|
||
if lo == -1 {
|
||
if n == 1 {
|
||
return 0, 0, a[0], true
|
||
}
|
||
return 0, 0, 0, false
|
||
}
|
||
|
||
// 第 3 步:V = b[lo],检查 [lo,hi] 内 b 全等于 V
|
||
V = b[lo]
|
||
for i := lo; i <= hi; i++ {
|
||
if b[i] != V {
|
||
return 0, 0, 0, false
|
||
}
|
||
}
|
||
|
||
// 第 4 步:L 唯一性
|
||
lOK := lo == 0 || b[lo-1] != V
|
||
// 第 5 步:R 唯一性
|
||
rOK := hi == n-1 || b[hi+1] != V
|
||
|
||
if !lOK || !rOK {
|
||
return 0, 0, 0, false
|
||
}
|
||
|
||
// 第 6 步:唯一解
|
||
return lo, hi, V, true
|
||
}
|
||
|
||
func TestUniqueRangeAssign(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
a, b []int
|
||
wantL int
|
||
wantR int
|
||
wantV int
|
||
wantOK bool
|
||
}{
|
||
{"唯一-全改", []int{0, 0}, []int{1, 1}, 0, 1, 1, true},
|
||
{"唯一-部分改", []int{0, 0, 0, 0, 0}, []int{1, 1, 1, 0, 0}, 0, 2, 1, true},
|
||
{"唯一-右扩", []int{0, 0, 0, 0, 0}, []int{0, 0, 1, 1, 1}, 2, 4, 1, true},
|
||
{"无解-内部b不一致", []int{0, 1, 0}, []int{1, 0, 1}, 0, 0, 0, false},
|
||
{"不唯一-R可扩", []int{0, 1, 1}, []int{1, 1, 1}, 0, 0, 0, false},
|
||
{"不唯一-L可扩", []int{1, 0, 1}, []int{1, 1, 1}, 0, 0, 0, false},
|
||
{"不唯一-a=b,n>=2", []int{1, 1, 1}, []int{1, 1, 1}, 0, 0, 0, false},
|
||
{"唯一-a=b,n=1", []int{0}, []int{0}, 0, 0, 0, true},
|
||
{"唯一-单点改", []int{0}, []int{1}, 0, 0, 1, true},
|
||
{"唯一-覆盖整个数组", []int{1, 1, 0, 1}, []int{0, 0, 0, 0}, 0, 3, 0, true},
|
||
{"无解-need不连续且b不一致", []int{0, 0, 0, 0}, []int{1, 0, 0, 1}, 0, 0, 0, false},
|
||
}
|
||
for _, c := range cases {
|
||
L, R, V, ok := uniqueRangeAssign(c.a, c.b)
|
||
pass := ok == c.wantOK &&
|
||
(!ok || (L == c.wantL && R == c.wantR && V == c.wantV))
|
||
if !pass {
|
||
t.Errorf("%s: a=%v b=%v -> [%d,%d,%d] ok=%v, want [%d,%d,%d] ok=%v",
|
||
c.name, c.a, c.b, L, R, V, ok, c.wantL, c.wantR, c.wantV, c.wantOK)
|
||
}
|
||
}
|
||
} |