求max(a)<min(b)的区间个数

给定两个长度都为N的整型数组a[N]和b[N],求满足如下条件的闭区间个数:在区间[l,r]上,a中的任意元素都比b中的任意元素小。

这个问题是O(N)复杂度。

两根指针l和r一前一后向后走,对于每个l,寻找最靠右的满足max(a[l:r])<min(b[l:r])的r值。r-l+1就表示如果以l为左区间,合法的r的个数。累加此值即可。关键在于:r的运动是单向的。

因为:如果在大区间[l,r]上满足max(a)<min(b),那么在[l+1,r]自区间上必然也满足max(a)<min(b),所以r是单向运动的。使用两个单调队列可以实现O(N)复杂度。

import java.util.LinkedList;
import java.util.Scanner; public class Main {
void pushMax(LinkedList<Integer> q, int value) {
while (!q.isEmpty() && q.getLast() < value) q.removeLast();
q.add(value);
} void pushMin(LinkedList<Integer> q, int value) {
while (!q.isEmpty() && q.getLast() > value) q.removeLast();
q.add(value);
} boolean ok(LinkedList<Integer> max, LinkedList<Integer> min) {
if (max.isEmpty() || min.isEmpty()) return true;
if (max.getFirst() < min.getFirst()) return true;
return false;
} void deq(LinkedList<Integer> q, int value) {
if (!q.isEmpty() && value == q.getFirst()) q.removeFirst();
} Main() {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) a[i] = cin.nextInt();
for (int i = 0; i < n; i++) b[i] = cin.nextInt();
int s = 0;
int r = 0;
LinkedList<Integer> maxQ = new LinkedList<>(), minQ = new LinkedList<>();
int lastR = -1;
for (int i = 0; i < n; i++) {
for (r = Math.max(r, i); r < n; r++) {
if (lastR != r) {
pushMax(maxQ, a[r]);
pushMin(minQ, b[r]);
lastR = r;
}
// System.out.println(maxQ + " " + minQ);
if (!ok(maxQ, minQ)) break;
}
s += r - i; deq(maxQ, a[i]);
deq(minQ, b[i]);
}
System.out.println(s);
} public static void main(String[] args) {
new Main();
}
}

求全部区间极值之和

给定数组a[N],可以确定(N+1)*N/2个区间,每个区间都有极大值、极小值,求所有区间的极大值、极小值之差。

问题可以转化为:求数字a[i]充当了几次极大值、充当了几次极小值,最终 极差之和$=\sum{a_i \times (maxCount-minCount)} $

关键在于如何求a[i]当了几次极大值、当了几次极小值。只需要知道从a[i]向左望去看到的第一个比a[i]大的值得坐标leftMax,向右望去看到的第一个比a[i]大的坐标rightMax,那么a[i]充当极大值的次数为$(i-leftMax) \times (rightMax-i)$

使用单调栈可以O(N)复杂度求出全部元素的左望最大和右望最大。

import java.util.Scanner;
import java.util.Stack; public class Main { Main() {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) a[i] = cin.nextInt();
int[] maxLeft = new int[n], maxRight = new int[n], minLeft = new int[n], minRight = new int[n];
Stack<Integer> maxStack = new Stack<>();
Stack<Integer> minStack = new Stack<>();
for (int i = 0; i < n; i++) {
while (!maxStack.isEmpty()) {
int index = maxStack.peek();
if (a[index] <= a[i]) {//此处等号是关键
maxStack.pop();
maxRight[index] = i;//index最右边能到达的位置
} else {
break;
}
}
int leftIndex = 0;
if (!maxStack.isEmpty()) leftIndex = maxStack.peek() + 1;
maxLeft[i] = leftIndex;
maxStack.push(i); while (!minStack.isEmpty()) {
int index = minStack.peek();
if (a[index] >= a[i]) {
minStack.pop();
minRight[index] = i;//index最左边能到达的位置
} else {
break;
}
}
int rightIndex = 0;
if (!minStack.isEmpty()) rightIndex = minStack.peek() + 1;
minLeft[i] = rightIndex;
minStack.push(i);
}
while (!maxStack.isEmpty()) {
maxRight[maxStack.pop()] = n;
}
while (!minStack.isEmpty()) {
minRight[minStack.pop()] = n;
}
int s = 0;
for (int i = 0; i < n; i++) {
int maxCount = (i - maxLeft[i] + 1) * (maxRight[i] - i), minCount = (i - minLeft[i] + 1) * (minRight[i] - i);
s += a[i] * (maxCount - minCount);
}
System.out.println(s);
} public static void main(String[] args) {
new Main();
}
}

数组问题常用的O(N)算法:单调队列的更多相关文章

  1. Codeforces Round #574 (Div. 2) E. OpenStreetMap 【单调队列】

    一.题目 OpenStreetMap 二.分析 对于二维空间找区间最小值,那么一维的很多好用的都无法用了,这里可以用单调队列进行查找. 先固定一个坐标,然后进行一维的单调队列操作,维护一个区间长度为$ ...

  2. 洛谷 P1714 切蛋糕 单调队列

    这个题比较显然,要用前缀和来做.但只用前缀和是过不去的,会TLE,所以需要进行优化. 对于每个前缀和数组 b 中的元素,都可以找到以 b[i] 结尾的子段最大值 p[i],显然,最终的 ans 就是 ...

  3. javascript中数组的常用算法深入分析

    Array数组是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array是前端必修的功课.本文将给大家详细介绍了javascri ...

  4. 操作 numpy 数组的常用函数

    操作 numpy 数组的常用函数 where 使用 where 函数能将索引掩码转换成索引位置: indices = where(mask) indices => (array([11, 12, ...

  5. Java的数组,集合,数据结构,算法(一)

    本人的愚见,博客是自己积累对外的输出,在学习初期或自己没有多少底料的情况下,与其总结写博客不如默默去搞自己的代码,但是学到集合这一块时,数组,集合,数据结构,算法这个概念搞的我比较混淆,所以不得已写这 ...

  6. Java实例 Part4:数组及其常用操作

    目录 Part4:数组及其常用操作 Example01:将二维数组的行列交换 Example02:使用选择排序法对数组进行排序 Example03:使用冒泡排序法对数组进行排序 Example04:使 ...

  7. 大数据学习day13------第三阶段----scala01-----函数式编程。scala以及IDEA的安装,变量的定义,条件表达式,for循环(守卫模式,推导式,可变参数以及三种遍历方式),方法定义,数组以及集合(可变和非可变),数组中常用的方法

    具体见第三阶段scala-day01中的文档(scala编程基础---基础语法)  1. 函数式编程(https://www.cnblogs.com/wchukai/p/5651185.html): ...

  8. php 数组的常用函数

    在php教程中数组是种强大的数据类型,他可以做的事情很多,可以存储不同的数据类型在一个数组中,下面我们列出了数组常用的操作,排序,键名对数组排序等做法. /* 数组的常用函数  *  * 数组的排序函 ...

  9. PHP数组的常用函数

    在PHP中数组是种强大的数据类型,他可以做的事情很多,可以存储不同的数据类型在一个数组中,下面我们列出了数组常用的操作,排序,键名对数组排序等做法. /* 数组的常用函数  *  * 数组的排序函数 ...

随机推荐

  1. 根据ip地址获取用户所在地

    java代码: package com.henu.controller; import java.io.BufferedReader; import java.io.IOException; impo ...

  2. HDU 1234 (浙大计算机研究生复试上机考试-2005年) 开门人和关门人 (水)

    开门人和关门人 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  3. Spring Boot集成持久化Quartz定时任务管理和界面展示

    本文是对之前的一篇文章Spring+SpringMVC+mybatis+Quartz整合代码部分做的一个修改和补充, 其中最大的变化就是后台框架变成了Spring Boot. 本工程所用到的技术或工具 ...

  4. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十三)kafka+spark streaming打包好的程序提交时提示虚拟内存不足(Container is running beyond virtual memory limits. Current usage: 119.5 MB of 1 GB physical memory used; 2.2 GB of 2.1 G)

    异常问题:Container is running beyond virtual memory limits. Current usage: 119.5 MB of 1 GB physical mem ...

  5. ACM~排列组合&amp;&amp;hdu例子

    排列组合是数学中的一个分支.在计算机编程方面也有非常多的应用,主要有排列公式和组合公式.错排公式.母函数.Catalan Number(卡特兰数)等. 一.有关组合数学的公式 1.排列公式   P(n ...

  6. 红米1线刷救砖教程V5版(移动联通适用,线刷包永久有效)

    红米1线刷救砖教程V5版(移动联通适用,线刷包永久有效) 原文来自:http://www.miui.com/thread-1890972-1-1.html?mobile=2 ,加了些自己的经验. (我 ...

  7. 安装QT的时候出现PATH_MAX错误

      运行c:\qt\4.5.0的configure文件的时候,出现如下的错误提示: ....\corelib\io\qfsfileengine_win.cpp(1012) : error C2065: ...

  8. 将java项目打包成docker镜像:镜像=副本

    简介:将jar打包成镜像好说,毕竟jar包长的都是一样的,但是我们只是写了一个普通的java项目,我也不方便封装成jar包什么的,但是我们也想打包docker image怎么办呢,我们可以用编译后的j ...

  9. pycharm下设置自己的模板

    在File---settings---File and Code Templates---Python script 脚本里添加: #!usr/bin/env python #-*- coding:u ...

  10. C#.NET常见问题(FAQ)-控制台程序如何做弹窗

    最简单的弹窗,只要引用System.Windows.Forms,就可以使用WinForm的弹窗   如果要弹出是/否的选择对话框,则可以拷贝下面的代码 DialogResult dr = Messag ...