2023-03-02:给定一个数组arr,长度为n, 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的! 求所有可能的合法子序列中,最大中位数是多少? 中位数的定义为上中位数, [1,
Posted 福大大架构师每日一题
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2023-03-02:给定一个数组arr,长度为n, 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的! 求所有可能的合法子序列中,最大中位数是多少? 中位数的定义为上中位数, [1,相关的知识,希望对你有一定的参考价值。
2023-03-02:给定一个数组arr,长度为n,
任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的!
求所有可能的合法子序列中,最大中位数是多少?
中位数的定义为上中位数,
[1, 2, 3, 4]的上中位数是2,
[1, 2, 3, 4, 5]的上中位数是3,
2 <= n <= 10^5,
1 <= arr[i] <= 10^9。
来自京东。实习岗位笔试题。
答案2023-03-02:
这道题看起来是实习题,实际上有难度。
方法一:要i还是不要i,递归或者动态规划。
方法二:以结果为导向,二分法。
时间复杂度:O(N*logN)。
空间复杂度:O(N)。
代码用rust编写。代码如下:
use rand::Rng;
use std::collections::HashMap;
use std::iter::repeat;
fn main()
let nn = 20;
let vv = 1000;
let test_times = 5000;
println!("测试开始");
for i in 0..test_times
let n = rand::thread_rng().gen_range(0, nn) + 1;
let mut arr = random_array(n, vv);
let ans1 = best_median1(&mut arr);
let ans2 = best_median2(&mut arr);
if ans1 != ans2
println!("出错了!");
return;
println!("测试结束");
fn valid_sub_max_sum(arr: &mut Vec<i32>) -> i32
return zuo(arr, 0, 1);
// 当前来到i位置
// 如果arr[i-1]位置的数选了,pre == 1
// 如果arr[i-1]位置的数没选,pre == 0
// arr[i....]最大合法子序列的累加和是多少
fn zuo(arr: &mut Vec<i32>, i: i32, pre: i32) -> i32
if i == arr.len() as i32
return 0;
// 还有数!
// 可能性1 : 不要i位置的数
let mut p1 = i32::MIN;
if pre == 1
p1 = zuo(arr, i + 1, 0);
// 可能性2 : 要i位置的数
let mut p2 = i32::MIN;
let mut next2 = zuo(arr, i + 1, 1);
if next2 != i32::MIN
p2 = arr[i as usize] + next2;
return if p1 > p2 p1 else p2 ;
// 启发函数
// 如果数组中的值只有1和-1,
// 你可以从左往右选择数字组成子序列,
// 但是要求任何两个相邻的数,至少要选1个
// 请返回子序列的最大累加和
// arr : 数组
// i : 当前来到i位置
// pre : 前一个数字(i-1位置),当初选了没有
// 如果pre == 0, 表示i-1位置的数字,当初没有选
// 如果pre == 1, 表示i-1位置的数字,当初选了
// 返回arr[i...]的子序列,最大累加和
fn max_sum(arr: &mut Vec<i32>, i: i32, pre: i32) -> i32
if i == arr.len() as i32
return 0;
// 可能性1 : 就是要选当前i位置的数
let mut p1 = arr[i as usize] + max_sum(arr, i + 1, 1);
// 可能性1 : 就是不选当前i位置的数
let mut p2 = -1;
if pre == 1
// 只有前一个数字选了,当前才能不选
p2 = max_sum(arr, i + 1, 0);
return if p1 > p2 p1 else p2 ;
// 暴力方法
// 为了验证
fn best_median1(arr: &mut Vec<i32>) -> i32
let mut path: Vec<i32> = repeat(0).take(arr.len()).collect();
return process(arr, 0, true, &mut path, 0);
fn process(arr: &mut Vec<i32>, i: i32, pre: bool, path: &mut Vec<i32>, size: i32) -> i32
if i == arr.len() as i32
if size == 0
return 0;
let mut sort: Vec<i32> = repeat(0).take(size as usize).collect();
for j in 0..size
sort[j as usize] = path[j as usize];
sort.sort();
return sort[(sort.len() - 1) / 2];
else
path[size as usize] = arr[i as usize];
let mut ans = process(arr, i + 1, true, path, size + 1);
if pre
ans = get_max(ans, process(arr, i + 1, false, path, size));
return ans;
fn get_max<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T
if a > b
a
else
b
// 正式方法
// 时间复杂度O(N*logN)
fn best_median2(arr: &mut Vec<i32>) -> i32
let n = arr.len() as i32;
let mut sort: Vec<i32> = repeat(0).take(n as usize).collect();
for i in 0..n
sort[i as usize] = arr[i as usize];
sort.sort();
// int[] arr = 5, 3, 6, 2, 9, 7 ;
// int[] sort = 2, 3, 5, 6, 7, 9 ;
// 0 1 2 3 4 5
// l r
let mut l = 0;
let mut r = n - 1;
let mut m = 0;
let mut ans = -1;
let mut help: Vec<i32> = repeat(0).take(n as usize).collect();
let mut dp: Vec<Vec<i32>> = repeat(repeat(0).take(2).collect())
.take((n + 1) as usize)
.collect();
while l <= r
m = (l + r) / 2;
if max_sum1(arr, &mut help, &mut dp, sort[m as usize], n) > 0
ans = sort[m as usize];
l = m + 1;
else
r = m - 1;
return ans;
// 如果中位数定成median,
// 如果任意相邻的两数,至少选一个,来生成序列
// 所有这样的序列中,
// 到底有没有一个序列,其中>= median的数字,能达到一半以上
fn max_sum1(
arr: &mut Vec<i32>,
help: &mut Vec<i32>,
dp: &mut Vec<Vec<i32>>,
median: i32,
n: i32,
) -> i32
for i in 0..n
help[i as usize] = if arr[i as usize] >= median 1 else -1 ;
let mut i = n - 1;
while i >= 0
dp[i as usize][0] = help[i as usize] + dp[(i + 1) as usize][1];
dp[i as usize][1] = get_max(
help[i as usize] + dp[(i + 1) as usize][1],
dp[(i + 1) as usize][0],
);
i -= 1;
return dp[0][1];
// 为了测试
fn random_array(n: i32, v: i32) -> Vec<i32>
let mut ans: Vec<i32> = repeat(0).take(n as usize).collect();
for i in 0..n
ans[i as usize] = rand::thread_rng().gen_range(0, v);
return ans;
以上是关于2023-03-02:给定一个数组arr,长度为n, 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的! 求所有可能的合法子序列中,最大中位数是多少? 中位数的定义为上中位数, [1,的主要内容,如果未能解决你的问题,请参考以下文章
2022-08-22:给定一个数组arr,长度为n,最多可以删除一个连续子数组, 求剩下的数组,严格连续递增的子数组最大长度。 n <= 10^6。 来自字节。5.6笔试。
2021-08-03:完美洗牌问题。给定一个长度为偶数的数组arr,假设长度为N*2,左部分:arr[L1……Ln],右部分: arr[R1……Rn],请把arr调整成arr[L1,R1,L2,R2,
2022-08-06:给定一个数组arr,长度为N,arr中所有的值都在1~K范围上, 你可以删除数字,目的是让arr的最长递增子序列长度小于K。 返回至少删除几个数字能达到目的。 N <= 10^4
给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数
给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数
2022-01-12:给定一个正数数组arr,长度为n,下标0~n-1, arr中的0n-1位置不需要达标,它们分别是最左最右的位置, 中间位置i需要达标,达标的条件是 : arr[i-1] >