拼多多笔试真题 10.11 - 测温共值最长段(C++/Py/Java /Js/Go)

测温共值最长段

拼多多 10月11号 笔试真题 第二题

拼多多真题目录点击查看: 拼多多笔试真题题库目录|笔试题库 + 算法考点详解

题目内容

机房按天记录服务器机柜温度。第 i i i 天的读数是一个闭区间 a i , b i a_i,b_i ai,bi,表示真实温度(取整数刻度)可能落在该区间内。共有 m m m 天记录,并按日期先后排列。

需要选出一段非空的连续日期 ,下标记为 p , q p,q p,q。在这段日期中,允许至多把一天的记录当作故障并丢弃 ,也可以一天都不丢。丢弃后至少还要留下一天记录,并且存在整数 t t t,落在每一条保留记录的闭区间内。换言之,未丢弃的那些天里,真实温度都有可能取同一个整数 t t t。

所选连续段的跨度定义为 q − p + 1 q-p+1 q−p+1;被丢弃的那一天仍然计入跨度。请给出合法跨度的最大值。

输入描述

首行给出整数 m m m( 1 ≤ m ≤ 2 × 10 5 1\le m\le 2\times 10^5 1≤m≤2×105),即记录天数。

第二行 m m m 个整数 a 1 , a 2 , ... , a m a_1,a_2,\dots,a_m a1,a2,...,am。

第三行 m m m 个整数 b 1 , b 2 , ... , b m b_1,b_2,\dots,b_m b1,b2,...,bm。

保证对每个 i i i 都有 1 ≤ a i ≤ b i ≤ 10 9 1\le a_i\le b_i\le 10^9 1≤ai≤bi≤109。本题仅一组数据。

输出描述

输出一个整数,即合法连续日期跨度的最大值。

样例1

输入

复制代码
5
1 2 8 3 4
5 4 9 6 7

输出

复制代码
5

说明

取全部 5 5 5 天,丢弃第 3 3 3 天的 8 , 9 8,9 8,9。其余四天都包含 4 4 4,长度为 5 5 5。

样例2

输入

复制代码
6
1 2 3 4 5 6
2 4 5 6 7 8

输出

复制代码
4

说明

例如取前 4 4 4 天并丢弃第 1 1 1 天,其余三天都包含 4 4 4。不存在长度为 5 5 5 的合法段。

样例3

输入

复制代码
2
1 100
1 100

输出

复制代码
2

说明

两天区间不相交,可丢弃其中任意一天,仍保留一天记录,故长度 2 2 2 合法。

题解

思路

解题算法:堆 + 滑动窗口

  1. 使用两个队维护,堆中的元素保存二元组 (值, 下标),方便判断元素是否已经离开滑动窗口。
    • maxHeap: 维护区间内a,按照从大到小排列
    • minHeap: 维护区间内b,按照从小到达排列
  2. 对于当前窗口[l,r], 设
    • A1:窗口最大a,A2窗口内第二大a
    • B1:窗口内最小b,B2窗口内第二小b
  3. 那么窗口的合法条件为A2 <= B1 || A1 <= B2 || A1 <= B1,分别对应
    • 删除最大aA2 <= B1
    • 删除最小B A1 <= B2
    • 不删除记录A1 <= B1
  4. 通过上述逻辑,移动窗口右边界,并计算以r结尾窗口的最小合法左边界l,即可当前合法窗口大小为r - l + 1, 对应记录其中出现最大合法窗口长度即可。
  5. 算法总体时间复杂度为O(mlogm)

C++

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

struct Node {
    int value, index;

    bool operator<(const Node& other) const {
        return value < other.value;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int m;
    cin >> m;

    vector<int> a(m), b(m);
    for (int i = 0; i < m; i++) cin >> a[i];
    for (int i = 0; i < m; i++) cin >> b[i];

    // 大顶堆:按照 a 从大到小排列
    priority_queue<Node> maxHeap;

    // 小顶堆:按照 b 从小到大排列
    priority_queue<Node, vector<Node>,
        function<bool(const Node&, const Node&)>> minHeap(
        [](const Node& x, const Node& y) {
            return x.value > y.value;
        }
    );

    int l = 0, ans = 1;

    for (int r = 0; r < m; r++) {
        // 将当前记录加入两个堆
        maxHeap.push({a[r], r});
        minHeap.push({b[r], r});

        while (true) {
            // 清理已经离开窗口的堆顶元素
            while (!maxHeap.empty() && maxHeap.top().index < l) {
                maxHeap.pop();
            }
            
            while (!minHeap.empty() && minHeap.top().index < l) {
                minHeap.pop();
            }

            int len = r - l + 1;
            if (len <= 1) break;

            // 获取 a 的最大值和第二大值
            Node firstA = maxHeap.top();
            maxHeap.pop();

            // 清理过期元素后,再获取第二大值
            while (!maxHeap.empty() && maxHeap.top().index < l) {
                maxHeap.pop();
            }

            Node secondA = maxHeap.top();
            maxHeap.push(firstA);

            // 获取 b 的最小值和第二小值
            Node firstB = minHeap.top();
            minHeap.pop();

            // 清理过期元素后,再获取第二小值
            while (!minHeap.empty() && minHeap.top().index < l) {
                minHeap.pop();
            }

            Node secondB = minHeap.top();
            minHeap.push(firstB);

            // 至多删除一天后,剩余区间必须存在公共交集
            if (secondA.value <= firstB.value ||
                firstA.value <= secondB.value) {
                break;
            }

            // 当前窗口不合法,缩小左边界
            l++;
        }

        ans = max(ans, r - l + 1);
    }

    cout << ans << '\n';
    return 0;
}

java

java 复制代码
import java.util.*;

public class Main {
    static class Node {
        int value, index;

        Node(int value, int index) {
            this.value = value;
            this.index = index;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();

        int[] a = new int[m];
        int[] b = new int[m];

        for (int i = 0; i < m; i++) a[i] = sc.nextInt();
        for (int i = 0; i < m; i++) b[i] = sc.nextInt();

        // 大顶堆:按照 a 从大到小排列
        PriorityQueue<Node> maxHeap = new PriorityQueue<>(
            (x, y) -> Integer.compare(y.value, x.value)
        );

        // 小顶堆:按照 b 从小到大排列
        PriorityQueue<Node> minHeap = new PriorityQueue<>(
            (x, y) -> Integer.compare(x.value, y.value)
        );

        int l = 0, ans = 1;

        for (int r = 0; r < m; r++) {
            // 将当前记录加入两个堆
            maxHeap.offer(new Node(a[r], r));
            minHeap.offer(new Node(b[r], r));

            while (true) {
                // 清理已经离开窗口的堆顶元素
                while (!maxHeap.isEmpty() && maxHeap.peek().index < l) {
                    maxHeap.poll();
                }
                while (!minHeap.isEmpty() && minHeap.peek().index < l) {
                    minHeap.poll();
                }

                int len = r - l + 1;
                if (len <= 1) break;

                // 获取 a 的最大值和第二大值
                Node firstA = maxHeap.poll();

                // 清理过期元素后,再获取第二大值
                while (!maxHeap.isEmpty() && maxHeap.peek().index < l) {
                    maxHeap.poll();
                }

                Node secondA = maxHeap.peek();
                maxHeap.offer(firstA);

                // 获取 b 的最小值和第二小值
                Node firstB = minHeap.poll();

                // 清理过期元素后,再获取第二小值
                while (!minHeap.isEmpty() && minHeap.peek().index < l) {
                    minHeap.poll();
                }

                Node secondB = minHeap.peek();
                minHeap.offer(firstB);

                // 至多删除一天后,剩余区间必须存在公共交集
                if (secondA.value <= firstB.value ||
                    firstA.value <= secondB.value) {
                    break;
                }

                // 当前窗口不合法,缩小左边界
                l++;
            }

            ans = Math.max(ans, r - l + 1);
        }

        System.out.println(ans);
        sc.close();
    }
}

python

python 复制代码
import sys
import heapq

def main():
    input = sys.stdin.readline

    m = int(input())
    a = list(map(int, input().split()))
    b = list(map(int, input().split()))

    # 大顶堆:通过负数实现,按照 a 从大到小排列
    maxHeap = []

    # 小顶堆:按照 b 从小到大排列
    minHeap = []

    l = 0
    ans = 1

    for r in range(m):
        # 将当前记录加入两个堆
        heapq.heappush(maxHeap, (-a[r], r))
        heapq.heappush(minHeap, (b[r], r))

        while True:
            # 清理已经离开窗口的堆顶元素
            while maxHeap and maxHeap[0][1] < l:
                heapq.heappop(maxHeap)

            while minHeap and minHeap[0][1] < l:
                heapq.heappop(minHeap)

            length = r - l + 1
            if length <= 1:
                break

            # 获取 a 的最大值和第二大值
            firstA = heapq.heappop(maxHeap)

            # 清理过期元素后,再获取第二大值
            while maxHeap and maxHeap[0][1] < l:
                heapq.heappop(maxHeap)

            secondA = maxHeap[0]
            heapq.heappush(maxHeap, firstA)

            # 获取 b 的最小值和第二小值
            firstB = heapq.heappop(minHeap)

            # 清理过期元素后,再获取第二小值
            while minHeap and minHeap[0][1] < l:
                heapq.heappop(minHeap)

            secondB = minHeap[0]
            heapq.heappush(minHeap, firstB)

            A1 = -firstA[0]
            A2 = -secondA[0]
            B1 = firstB[0]
            B2 = secondB[0]

            # 至多删除一天后,剩余区间必须存在公共交集
            if A2 <= B1 or A1 <= B2:
                break

            # 当前窗口不合法,缩小左边界
            l += 1

        ans = max(ans, r - l + 1)

    print(ans)

if __name__ == "__main__":
    main()

Go

go 复制代码
package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

type Node struct {
	value int
	index int
}

// 大顶堆:按照 a 从大到小排列
type MaxHeap []Node

func (h MaxHeap) Len() int           { return len(h) }
func (h MaxHeap) Less(i, j int) bool { return h[i].value > h[j].value }
func (h MaxHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *MaxHeap) Push(x interface{}) {
	*h = append(*h, x.(Node))
}

func (h *MaxHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[:n-1]
	return x
}

// 小顶堆:按照 b 从小到大排列
type MinHeap []Node

func (h MinHeap) Len() int           { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i].value < h[j].value }
func (h MinHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *MinHeap) Push(x interface{}) {
	*h = append(*h, x.(Node))
}

func (h *MinHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[:n-1]
	return x
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	writer := bufio.NewWriter(os.Stdout)
	defer writer.Flush()

	var m int
	fmt.Fscan(reader, &m)

	a := make([]int, m)
	b := make([]int, m)

	for i := 0; i < m; i++ {
		fmt.Fscan(reader, &a[i])
	}
	for i := 0; i < m; i++ {
		fmt.Fscan(reader, &b[i])
	}

	maxHeap := &MaxHeap{}
	minHeap := &MinHeap{}
	heap.Init(maxHeap)
	heap.Init(minHeap)

	l, ans := 0, 1

	for r := 0; r < m; r++ {
		// 将当前记录加入两个堆
		heap.Push(maxHeap, Node{a[r], r})
		heap.Push(minHeap, Node{b[r], r})

		for {
			// 清理已经离开窗口的堆顶元素
			for maxHeap.Len() > 0 && (*maxHeap)[0].index < l {
				heap.Pop(maxHeap)
			}
			for minHeap.Len() > 0 && (*minHeap)[0].index < l {
				heap.Pop(minHeap)
			}

			length := r - l + 1
			if length <= 1 {
				break
			}

			// 获取 a 的最大值和第二大值
			firstA := heap.Pop(maxHeap).(Node)

			// 清理过期元素后,再获取第二大值
			for maxHeap.Len() > 0 && (*maxHeap)[0].index < l {
				heap.Pop(maxHeap)
			}

			secondA := (*maxHeap)[0]
			heap.Push(maxHeap, firstA)

			// 获取 b 的最小值和第二小值
			firstB := heap.Pop(minHeap).(Node)

			// 清理过期元素后,再获取第二小值
			for minHeap.Len() > 0 && (*minHeap)[0].index < l {
				heap.Pop(minHeap)
			}

			secondB := (*minHeap)[0]
			heap.Push(minHeap, firstB)

			// 至多删除一天后,剩余区间必须存在公共交集
			if secondA.value <= firstB.value ||
				firstA.value <= secondB.value {
				break
			}

			// 当前窗口不合法,缩小左边界
			l++
		}

		if r-l+1 > ans {
			ans = r - l + 1
		}
	}

	fmt.Fprintln(writer, ans)
}

javascript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const lines = [];

rl.on('line', line => {
    lines.push(line.trim());
});

rl.on('close', () => {
    const m = Number(lines[0]);
    const a = lines[1].split(/\s+/).map(Number);
    const b = lines[2].split(/\s+/).map(Number);

    // 大顶堆:按照 a 从大到小排列
    class MaxHeap {
        constructor() {
            this.heap = [];
        }

        push(node) {
            const h = this.heap;
            h.push(node);
            let i = h.length - 1;

            while (i > 0) {
                const p = (i - 1) >> 1;
                if (h[p].value >= h[i].value) break;
                [h[p], h[i]] = [h[i], h[p]];
                i = p;
            }
        }

        pop() {
            const h = this.heap;
            const top = h[0];
            const last = h.pop();

            if (h.length > 0) {
                h[0] = last;
                let i = 0;

                while (true) {
                    let best = i;
                    const left = i * 2 + 1;
                    const right = i * 2 + 2;

                    if (left < h.length &&
                        h[left].value > h[best].value) {
                        best = left;
                    }
                    if (right < h.length &&
                        h[right].value > h[best].value) {
                        best = right;
                    }
                    if (best === i) break;

                    [h[i], h[best]] = [h[best], h[i]];
                    i = best;
                }
            }

            return top;
        }

        peek() {
            return this.heap[0];
        }

        get size() {
            return this.heap.length;
        }
    }

    // 小顶堆:按照 b 从小到大排列
    class MinHeap {
        constructor() {
            this.heap = [];
        }

        push(node) {
            const h = this.heap;
            h.push(node);
            let i = h.length - 1;

            while (i > 0) {
                const p = (i - 1) >> 1;
                if (h[p].value <= h[i].value) break;
                [h[p], h[i]] = [h[i], h[p]];
                i = p;
            }
        }

        pop() {
            const h = this.heap;
            const top = h[0];
            const last = h.pop();

            if (h.length > 0) {
                h[0] = last;
                let i = 0;

                while (true) {
                    let best = i;
                    const left = i * 2 + 1;
                    const right = i * 2 + 2;

                    if (left < h.length &&
                        h[left].value < h[best].value) {
                        best = left;
                    }
                    if (right < h.length &&
                        h[right].value < h[best].value) {
                        best = right;
                    }
                    if (best === i) break;

                    [h[i], h[best]] = [h[best], h[i]];
                    i = best;
                }
            }

            return top;
        }

        peek() {
            return this.heap[0];
        }

        get size() {
            return this.heap.length;
        }
    }

    const maxHeap = new MaxHeap();
    const minHeap = new MinHeap();

    let l = 0;
    let ans = 1;

    for (let r = 0; r < m; r++) {
        // 将当前记录加入两个堆
        maxHeap.push({ value: a[r], index: r });
        minHeap.push({ value: b[r], index: r });

        while (true) {
            // 清理已经离开窗口的堆顶元素
            while (maxHeap.size && maxHeap.peek().index < l) {
                maxHeap.pop();
            }
            while (minHeap.size && minHeap.peek().index < l) {
                minHeap.pop();
            }

            const len = r - l + 1;
            if (len <= 1) break;

            // 获取 a 的最大值和第二大值
            const firstA = maxHeap.pop();

            // 清理过期元素后,再获取第二大值
            while (maxHeap.size && maxHeap.peek().index < l) {
                maxHeap.pop();
            }

            const secondA = maxHeap.peek();
            maxHeap.push(firstA);

            // 获取 b 的最小值和第二小值
            const firstB = minHeap.pop();

            // 清理过期元素后,再获取第二小值
            while (minHeap.size && minHeap.peek().index < l) {
                minHeap.pop();
            }

            const secondB = minHeap.peek();
            minHeap.push(firstB);

            // 至多删除一天后,剩余区间必须存在公共交集
            if (secondA.value <= firstB.value ||
                firstA.value <= secondB.value) {
                break;
            }

            // 当前窗口不合法,缩小左边界
            l++;
        }

        ans = Math.max(ans, r - l + 1);
    }

    console.log(ans);
});
相关推荐
无限码力1 个月前
拼多多笔试真题 - 班次连窗日均(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试题目题解·拼多多题库·拼多多机试真题
无限码力1 个月前
拼多多笔试真题题解 - 并箱放行(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多笔试题解·拼多多9月6号笔试真题
无限码力1 个月前
拼多多笔试真题 9.6 - 看旗派舟(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试·拼多多笔试真题题解·拼多多9月6号笔试真题
无限码力1 个月前
拼多多笔试真题 9.6 - 限次罐笼(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试真题题解·拼多多笔试题解·拼多多9月6号笔试真题
无限码力2 个月前
拼多多笔试真题 2026-8-30【唯一入栈出库序列】
算法·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多最新笔试题库
无限码力2 个月前
2026-8-30拼多多笔试真题-哪个查阅窗能留空(C++/Py/Java /Js/Go)
算法·pdd·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多笔试题解
无限码力2 个月前
pdd笔试真题-和差方程最少标定(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·pdd笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试·拼多多笔试题解
无限码力2 个月前
拼多多 春招&秋招 笔试真题题库目录|笔试题库 + 算法考点详解
算法·pdd笔试真题·pdd笔试真题题解·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解
无限码力2 个月前
pdd笔试真题-驿站补给最短耗时(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多机试·拼多多技术岗笔试·pdd笔试真题·拼多多技术岗笔试真题·pdd笔试真题题解