2022-04-17:给定一个数组arr,其中的值有可能正、负、0, 给定一个正数k。 返回累加和>=k的所有子数组中,最短的子数组长度。 来自字节跳动。力扣862。

答案2022-04-17:

看到子数组,联想到结尾怎么样,开头怎么样。 预处理前缀和,单调栈。 达标的前缀和,哪一个离k最近? 单调栈+二分。复杂度是O(N*logN)。 双端队列。 时间复杂度:O(N)。

代码用rust编写。代码如下:

fn main() {
    let arr: Vec<isize> = vec![2, -1, 2];
    let K: isize = 3;
    let ret = shortest_subarray2(arr, K);
    println!("{}", ret);
}

const MAXVALUE: isize = 9223372036854775807;

fn shortest_subarray2(arr: Vec<isize>, K: isize) -> isize {
    let N = arr.len();
    let mut sum: Vec<isize> = vec![];
    for i in 0..N + 1 {
        sum.push(0);
    }
    for i in 0..N {
        sum[i + 1] = sum[i] + arr[i];
    }
    let mut ans: isize = MAXVALUE;
    let mut dq: Vec<isize> = vec![];
    for i in 0..N + 1 {
        dq.push(0);
    }
    let mut l: isize = 0;
    let mut r: isize = 0;
    for i in 0..N + 1 {
        // 头部开始,符合条件的,从头部弹出!
        while l != r && sum[i] - sum[dq[l as usize] as usize] >= K {
            ans = get_min(ans, i as isize - dq[l as usize]);
            l += 1;
        }
        // 尾部开始,前缀和比当前的前缀和大于等于的,从尾部弹出!
        while l != r && sum[dq[(r - 1) as usize] as usize] >= sum[i as usize] {
            r -= 1;
        }
        dq[r as usize] = i as isize;
        r += 1;
    }
    if ans != MAXVALUE {
        ans
    } else {
        -1
    }
}

fn get_min(a: isize, b: isize) -> isize {
    if a < b {
        a
    } else {
        b
    }
}

执行结果如下:

在这里插入图片描述


左神java代码