Solution
这是一道技巧类的题;
如果用DP, 即便排了序, 比如当前数是9
, 与他匹配的有4, 3, 2, 1
是很多的可能, 即便我们选择4
, 那么 他的状态转移 即前面的状态 可以是8, 3
7, 3
… 也是很多的, 而且8 > 4
, 因此不符合DP的线性递推;
@Delimiter
我们对数组 (长度
n
n
n) 进行排序, 本题的关键 是要知道: 假如有
k
k
k对匹配 (不一定是最大匹配), 它必然满足以下几个性质:
1
2
∗
k
≤
n
2 * k \leq n
2∗k≤n;
2
假设开头最小的
k
k
k个元素是
a
1
,
.
.
.
,
a
k
a_1, ..., a_k
a1,...,ak, 末尾最大的
k
k
k个元素是
b
1
,
.
.
.
,
b
k
b_1, ..., b_k
b1,...,bk, 那么: 匹配
(
a
1
,
b
1
)
,
.
.
.
,
(
a
i
,
b
i
)
(a_1, b_1), ..., (a_i, b_i)
(a1,b1),...,(ai,bi) 一定是一个方案;
性质-2 非常非常重要, 它不一定是唯一方案, 但一定是一个合法方案;
比如: 1, 2, 3, 5, 6, 7
, 我们让k = 2
, 显然(1,6) (2,7)
不是唯一方案 (但他是合法方案), 比如(2,5) (3,6)
也是合法的;
你可以证明, 如果有k
个匹配, 那么其一定可以通过转换 变成"性质-2"的形式;
因此, 性质-2 是本题的关键;
@Delimiter
算法1: 你可以使用"二分"来枚举这个k
;
算法2: 可以使用双指针, 但这比较有难度, 它和"性质2"并不完全相同 有一些改动;
.
用一个l
指针 来表示:
[
0
,
.
.
.
,
l
−
1
]
[0, ..., l-1]
[0,...,l−1]这些元素 一定可以匹配;
.
但r
指针 并不就是指上面"性质-2"说的 (最大的k
个元素的下标), 而是: 因为和
[
0
,
.
.
.
,
l
−
1
]
[0, ..., l-1]
[0,...,l−1]这些元素 所匹配的
[
c
,
c
+
1
,
c
+
2
,
.
.
.
,
c
c
]
[c, c+1, c+2, ..., cc]
[c,c+1,c+2,...,cc] (注意
c
c
cc
cc并不一定是
n
−
1
n-1
n−1, 虽然按照上面的"性质-2",
c
c
cc
cc应该等于
n
−
1
n-1
n−1), 这些所匹配的元素 有个性质, 就是一定是递增的, 因此只要
[
.
.
.
,
l
−
1
,
l
]
[..., l-1, l]
[...,l−1,l] 能和
[
.
.
.
,
r
−
1
,
r
]
[..., r-1, r]
[...,r−1,r]能够匹配jik
.
.
比如,
1
,
2
,
3
,
4
,
5
,
6
,
7
1, 2, 3, 4, 5, 6, 7
1,2,3,4,5,6,7, 对于
[
1
,
2
]
[1, 2]
[1,2]这两个元素, 我们可以选择其与
[
3
,
4
]
[3,4]
[3,4]匹配, 但这么做就错了, 因为, 根据"性质-1"
2
∗
k
≤
n
2 * k \leq n
2∗k≤n, 任何一个匹配 都应该是: (一个属于
[
0
,
.
.
.
,
m
i
d
]
[0,..., mid]
[0,...,mid], 另一个属于
[
m
i
d
+
1
,
.
.
.
,
n
−
1
]
[mid+1, ...,n-1]
[mid+1,...,n−1]), 因此,
[
1
,
2
]
[1,2]
[1,2] 至少是应该和
[
5
,
6
]
[5,6]
[5,6]进行匹配;
故我们需要添加限制, 令 m i d = ( n + 1 ) / 2 mid = (n + 1)/2 mid=(n+1)/2, 则 l ∈ [ 0 , m i d ) , r ∈ [ m i d , n ) l \in [0, mid), r \in [mid, n) l∈[0,mid),r∈[mid,n), 即, 每个 r r r必然都是大于 l l l的;
而且, 我们最终得到的方案, 其实和"性质-2"不完全相同 (当然, 我们的根本 就是得到最大匹配k
, 只要得到k
就可以了)
比如, [1, 10, 11, 12]
, 我们第一次l = 1, r = 11
是一个匹配, 然后就没有了, 因此, 如果从双指针算法看, 我们得到的匹配的是
(
1
,
11
)
(1,11)
(1,11), 而不是
(
1
,
12
)
(1,12)
(1,12), 但总之 能得到最大匹配就可以了;
Code
int maxNumOfMarkedIndices(vector<int>& A) {
sort( A.begin(), A.end());
//--
int n = A.size();
int r = (n + 1) / 2;
int l;
for( l = 0; l < (n + 1) / 2; ++l){
while( r < n && A[l] * 2 > A[r]){
++ r;
}
if( r >= n){ return l * 2;}
//--
++ r;
}
return l * 2;
}