题目描述
找一个出现大于 ( n + 1 ) / 2 (n+1)/2 (n+1)/2次数的数,保证有解。
这道题说实话不好做:卡时间,卡空间。dp应该是正解。
(dp) O ( n ) O(n) O(n)
设答案解为 x,那么可以转换思路。
将原数组变为
a
[
i
]
=
(
a
[
i
]
=
=
x
)
?
1
:
−
1
a[i] = (a[i] == x) ? 1 : -1
a[i]=(a[i]==x)?1:−1,与最大子数组和的问题很像。
(1) 存在某个时候
m
a
x
_
v
a
l
=
x
max\_val = x
max_val=x,即证明存在
m
a
x
_
c
n
t
=
0
max\_cnt = 0
max_cnt=0(就是前缀和)
数组前缀和
s
u
m
(
n
)
>
=
0
sum(n) >= 0
sum(n)>=0, 假设不存在
s
u
m
(
i
)
=
0
sum(i) = 0
sum(i)=0(此时
m
a
x
_
c
n
t
=
0
max\_cnt = 0
max_cnt=0) 那么根据零点存在性定理,(可能有人会喷我这里说变量不是连续的,但是不可能出现 -1到1的突变)因此说不存在
s
u
m
(
i
)
<
0
sum(i) < 0
sum(i)<0, 所以保证数组从头到尾
s
u
m
(
i
)
>
=
0
sum(i) >= 0
sum(i)>=0, 此时可以保证找到x。
如果存在 s u m ( i ) < 0 sum(i) < 0 sum(i)<0 ,那么同样的根据 s u m ( n ) > = 0 sum(n) >= 0 sum(n)>=0, 可以保证存在 s u m ( k ) = 0 sum(k) = 0 sum(k)=0,即有 m a x _ c n t = 0 max\_cnt = 0 max_cnt=0。
(2) 设遍历到 i 的时候
m
a
x
_
v
a
l
=
x
max\_val = x
max_val=x, 此时
m
a
x
_
c
n
t
=
0
max\_cnt = 0
max_cnt=0.
那么剩下的数有
n
−
i
n - i
n−i 个, 假设剩下的 x 导致最后的
m
a
x
_
v
a
l
≠
x
max\_val \ne x
max_val=x, 那么表明剩下的x 的个数小于
(
n
−
i
+
1
)
/
2
(n - i + 1)/ 2
(n−i+1)/2,而之前的i个数中,i出现的个数不大于
i
/
2
i / 2
i/2, 因为此时在位置 i 才刚刚等于 x,加起来 x 的出现个数小于
(
n
+
1
)
/
2
(n + 1) / 2
(n+1)/2, 与 x 的出现个数至少为
(
n
+
1
)
/
2
(n + 1) / 2
(n+1)/2 矛盾,因此假设不成立。
所以可以保证最后的 m a x _ v a l = x max\_val = x max_val=x
(3)实现:x 不可能提前知道。所以使用动态规划的思路实现。
设
d
p
[
i
]
dp[i]
dp[i]为前i个数中,满足出现个数至少为
(
i
+
1
)
/
2
(i + 1) / 2
(i+1)/2 的解。(解只可能有一个)
设
f
[
i
]
f[i]
f[i] 为前i个数中,
d
p
[
i
]
dp[i]
dp[i] 出现的个数(使用加一减一计数)。
如果
f
[
i
−
1
]
>
0
f[i - 1] > 0
f[i−1]>0,那么
d
p
[
i
]
=
d
p
[
i
−
1
]
,
f
[
i
]
=
f
[
i
−
1
]
+
(
a
[
i
]
=
=
d
p
[
i
]
)
dp[i] = dp[i - 1], f[i] = f[i - 1] + (a[i] == dp[i])
dp[i]=dp[i−1],f[i]=f[i−1]+(a[i]==dp[i])
如果
f
[
i
−
1
]
=
0
f[i - 1] = 0
f[i−1]=0, 那么表明前
i
−
1
i - 1
i−1个数无解,
d
p
[
i
]
=
a
[
i
]
,
f
[
i
]
=
1
dp[i] = a[i], f[i] = 1
dp[i]=a[i],f[i]=1,开启新的阶段。
由于只使用到了前后递推,所以使用两个变量滚动数组即可: d p [ i ] = m a x _ v a l , f [ i ] = m a x _ c n t . dp[i] = max\_val, f[i] = max\_cnt. dp[i]=max_val,f[i]=max_cnt.
由于 ( 1 ) ( 2 ) (1)(2) (1)(2)的证明,可以得到最后的 m a x _ v a l = x max\_val = x max_val=x
C++ 代码
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n;
int main() {
while (~scanf("%d", &n)) {
int max_val = 0, max_cnt = 0;
for (int i = 0; i < n; i++) {
int temp;
scanf("%d", &temp);
if (max_cnt == 0) {
max_cnt = 1;
max_val = temp;
} else {
max_cnt += (temp == max_val ? 1 : -1);
}
}
cout << max_val << endl;
}
}