结队编程 - 华为OD统一考试(D卷)

OD统一考试(D卷)

分值: 200分

题解: Java / Python / C++

华为od机试真题

题目描述

某部门计划通过结队编程来进行项目开发,已知该部门有 N 名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程,结队分组规则如下:

从部门中选出序号分别为 i、j、k 的3名员工,他们的职级分别为 level[i],level[j],level[k],结队小组满足 level[i] < level[j] < level[k] 或者 level[i] > level[j] > level[k],其中 0 ≤ i < j < k < n。

请你按上述条件计算可能组合的小组数量。同一员工可以参加多个小组。

输入描述

第一行输入:员工总数 n

第二行输入:按序号依次排列的员工的职级 level,中间用空格隔开

备注:

1 <= n <= 6000

1 <= level[i] <= 10^5

输出描述

可能结队的小组数量

示例1

输入:
4
1 2 3 4

输出:
4

说明:
可能结队成的组合(1,2,3)、(1,2,4)、(1,3,4)、(2,3,4)

示例2

输入:
3
5 4 7

输出:
0

说明:
根据结队条件,我们无法为该部门组建小组

题解

这个问题可以通过使用单调栈来优化组合计算。

具体来说,我们可以分别利用两个单调栈来维护每个员工左侧和右侧的符合条件的员工数量,从而避免三重循环带来的高时间复杂度。

算法步骤

  1. 预处理左侧数据:

    • 使用两个单调栈分别计算每个员工左侧大于和小于当前职级的员工数量。
  2. 预处理右侧数据:

    • 使用两个单调栈分别计算每个员工右侧大于和小于当前职级的员工数量。
  3. 计算满足条件的组合数量:

    • 使用预处理得到的左侧和右侧的数据,计算符合条件的组合数量。

时间复杂度: O(n)

Java

import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] levels = new int[n];
        for (int i = 0; i < n; i++) {
            levels[i] = scanner.nextInt();
        }

        int[] gt = new int[n];  // 左侧小于当前职级的员工数量
        int[] lt = new int[n];  // 左侧大于当前职级的员工数量

        Stack<Integer> maxStack = new Stack<>();
        Stack<Integer> minStack = new Stack<>();

        // 计算左侧数据
        for (int i = 0; i < n; i++) {
            while (!maxStack.isEmpty() && levels[i] >= levels[maxStack.peek()]) {
                maxStack.pop();
            }
            lt[i] = maxStack.size();

            while (!minStack.isEmpty() && levels[i] <= levels[minStack.peek()]) {
                minStack.pop();
            }
            gt[i] = minStack.size();

            maxStack.push(i);
            minStack.push(i);
        }

        long ans = 0;
        maxStack.clear();
        minStack.clear();

        // 计算右侧数据并统计结果
        for (int i = n - 1; i >= 0; i--) {
            while (!maxStack.isEmpty() && levels[i] >= levels[maxStack.peek()]) {
                maxStack.pop();
            }
            ans += (long) maxStack.size() * gt[i];

            while (!minStack.isEmpty() && levels[i] <= levels[minStack.peek()]) {
                minStack.pop();
            }
            ans += (long) minStack.size() * lt[i];

            maxStack.push(i);
            minStack.push(i);
        }

        System.out.println(ans);
    }
}

Python

n = int(input())
level = list(map(int, input().split()))

max_stack, min_stack = [], []
gt, lt = [0] * n, [0]*n

# 计算左侧数据
for i, v in enumerate(level):
    while max_stack and v >= max_stack[-1]:
        max_stack.pop()
    lt[i] = len(max_stack)

    while min_stack and v <= min_stack[-1]:
        min_stack.pop()
    gt[i] = len(min_stack)

    max_stack.append(v)
    min_stack.append(v)


ans = 0
max_stack, min_stack = [], []
# 计算右侧数据并统计结果
for i in range(n-1, -1, -1):
    v = level[i]
    while max_stack and v >= max_stack[-1]:
        max_stack.pop()
    ans += len(max_stack) * gt[i]

    while min_stack and v <= min_stack[-1]:
        min_stack.pop()
    ans += len(min_stack) * lt[i]

    max_stack.append(level[i])
    min_stack.append(level[i])


print(ans)

C++

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> level(n);
    for (int i = 0; i < n; ++i) {
        cin >> level[i];
    }

    vector<int> gt(n, 0), lt(n, 0);
    stack<int> maxStack, minStack;

    // 计算左侧数据
    for (int i = 0; i < n; ++i) {
        while (!maxStack.empty() && level[i] >= level[maxStack.top()]) {
            maxStack.pop();
        }
        lt[i] = maxStack.size();

        while (!minStack.empty() && level[i] <= level[minStack.top()]) {
            minStack.pop();
        }
        gt[i] = minStack.size();

        maxStack.push(i);
        minStack.push(i);
    }

    long long ans = 0;
    while (!maxStack.empty()) maxStack.pop();
    while (!minStack.empty()) minStack.pop();

    // 计算右侧数据并统计结果
    for (int i = n - 1; i >= 0; --i) {
        while (!maxStack.empty() && level[i] >= level[maxStack.top()]) {
            maxStack.pop();
        }
        ans += static_cast<long long>(maxStack.size()) * gt[i];

        while (!minStack.empty() && level[i] <= level[minStack.top()]) {
            minStack.pop();
        }
        ans += static_cast<long long>(minStack.size()) * lt[i];

        maxStack.push(i);
        minStack.push(i);
    }

    cout << ans << endl;
    return 0;
}

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

#华为od题库##华为od机试##华为od##华为OD机试算法题库#
全部评论
请问一下为什么使用单调栈呢?单调栈不会造成漏算吗?
点赞 回复 分享
发布于 02-05 00:59 四川

相关推荐

头顶尖尖的程序员:我也是面了三四次才放平心态的。准备好自我介绍,不一定要背熟,可以记事本写下来读。全程控制语速,所有问题都先思考几秒,不要急着答,不要打断面试官说话。
点赞 评论 收藏
分享
05-16 11:16
已编辑
东华理工大学 Java
牛客73769814...:盲猜几十人小公司,庙小妖风大,咋不叫她去4️⃣呢😁
牛客创作赏金赛
点赞 评论 收藏
分享
评论
4
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务