当前位置: 首页 > news >正文

牛客NC288803 和+和

 ​
 import java.util.Comparator;
 import java.util.PriorityQueue;
 import java.util.Scanner;
 ​
 public class Main {
     public static void main(String[] args) {
         // 创建Scanner对象用于读取输入
         Scanner sc = new Scanner(System.in);
         // 读取两个整数n和m,分别表示数组的长度和窗口的大小
         int n = sc.nextInt(); 
         int m = sc.nextInt();
         // 初始化两个数组a和b,用于存储输入的两个数组
         long a[] = new long[n + 1];
         long b[] = new long[n + 1];
         // 读取数组a的元素
         for (int i = 1; i <= n; i++) a[i] = sc.nextLong();
         // 读取数组b的元素
         for (int i = 1; i <= n; i++) b[i] = sc.nextLong();
         // 初始化前缀和数组pre和后缀和数组hen
         long pre[] = new long[n + 1];
         long hen[] = new long[n + 1];
         // 创建两个优先队列,用于维护窗口内的最大值
         PriorityQueue<Long> q1 = new PriorityQueue<>(Comparator.reverseOrder());
         PriorityQueue<Long> q2 = new PriorityQueue<>(Comparator.reverseOrder());
         
         // 计算数组a的前缀和
         for (int i = 1; i <= m; i++) {
             pre[i] = pre[i - 1] + a[i];
         }
         // 计算数组b的后缀和
         hen[n] = b[n];
         for (int i = n - 1; i >= n - m + 1; i--) {
             hen[i] = hen[i + 1] + b[i];
         }
         
         // 维护数组a的窗口最大值
         for (int i = 1; i <= n; i++) {
             q1.add(a[i]);
             if (q1.size() > m) {
                 long t1 = q1.poll();
                 pre[i] = pre[i - 1];
                 pre[i] += (a[i] - t1);
             }
         }
         // 维护数组b的窗口最大值
         for (int i = n; i >= 1; i--) {
             q2.add(b[i]);
             if (q2.size() > m) {
                 long t2 = q2.poll();
                 hen[i] = hen[i + 1];
                 hen[i] += (b[i] - t2);
             }
         }
         
         // 枚举分界点,计算最小值
         long ans = Long.MAX_VALUE;
         for (int i = m; i <= n - m; i++) {
             ans = Math.min(ans, pre[i] + hen[i + 1]);
         }
         // 输出结果
         System.out.println(ans);
     }
 }
 ​
  1. 基本语法

    • 变量声明和初始化。

    • 循环结构(for循环)。

    • 条件判断(if语句)。

  2. 数据结构

    • 数组(long[])的使用,用于存储输入的数组和前缀和、后缀和。

    • PriorityQueue优先队列的使用,用于维护一个动态的窗口最大值。

    在Java中,PriorityQueue 是一个基于优先级堆的无界优先队列,它使用自然排序或者通过在构造器中指定的 Comparator 来排序其元素。以下是关于 PriorityQueue 在这段代码中如何用于维护一个动态窗口最大值的详细解释: PriorityQueue 的基本特性: 优先级排序:PriorityQueue 会根据元素的优先级顺序来排列元素。默认情况下,它是一个最小堆,但你可以通过传递一个 Comparator 实例来使其成为一个最大堆。 动态调整:当元素被添加到队列中或者从队列中移除时,PriorityQueue 会自动调整元素的位置以保持堆的特性。 在代码中的应用: 在提供的代码片段中,PriorityQueue 被用来维护滑动窗口中的最大值。这里是具体的应用步骤: 初始化两个优先队列: PriorityQueue<Long> q1 = new PriorityQueue<>(Comparator.reverseOrder()); PriorityQueue<Long> q2 = new PriorityQueue<>(Comparator.reverseOrder()); 这里创建了两个最大堆,q1 和 q2,分别用于处理数组 a 和 b 的元素。 填充优先队列: 在处理数组时,代码会将窗口内的元素添加到对应的优先队列中。例如,对于数组 a,代码可能会这样做: for (int i = 0; i < m; i++) { q1.add(a[i]); } 这样,q1 中就包含了数组 a 的前 m 个元素,且队列的头部始终是这 m 个元素中的最大值。 维护窗口: 当窗口在数组上滑动时,需要从队列中移除窗口前面的元素,并添加新的元素。例如: if (q1.size() > m) { q1.poll(); // 移除窗口前面的元素 } q1.add(a[i]); // 添加新的元素到窗口 通过这种方式,q1 始终保持窗口内的最大值在队列头部。 获取窗口最大值: 由于 q1 是一个最大堆,所以队列头部的元素就是窗口内的最大值。可以使用 q1.peek() 来获取这个值而不移除它,或者使用 q1.poll() 来获取并移除这个值。 为什么使用 PriorityQueue? 使用 PriorityQueue 而不是其他数据结构(如数组或列表)的原因是它可以更高效地维护窗口的最大值。在数组或列表中,每次窗口滑动时,都需要遍历窗口内的所有元素来找到最大值,这会导致时间复杂度为 O(m)。而使用 PriorityQueue,添加和移除元素的操作的时间复杂度是 O(log m),因此总体上可以更高效地处理滑动窗口问题。 总之,PriorityQueue 在这段代码中用于动态地跟踪和维护滑动窗口中的最大值,这是解决某些特定类型数组问题的有效方法。

  3. 算法

    • 前缀和算法,用于计算数组前i个元素的和。

    • 后缀和算法,用于计算数组从第i个元素到末尾的和。

    • 滑动窗口算法,通过优先队列来维护窗口内的最大值。

  4. Java标准库

    • Scanner类的使用,用于读取输入。

    • Comparator接口的使用,用于定义优先队列的排序规则。

      在Java中,Comparator接口是一个功能强大的工具,它允许程序员定义自己的排序规则,而不必依赖于对象类的自然排序(即实现Comparable接口的排序)。Comparator接口在许多场景中都非常有用,尤其是在使用集合框架中的排序和搜索操作时,比如在PriorityQueue、TreeSet或Collections.sort()方法中。 以下是关于Comparator接口的进一步解释: Comparator接口的基本概念: Comparator是一个函数式接口,这意味着它只有一个抽象方法,即compare(T o1, T o2),它用于比较两个类型为T的对象。 compare方法接受两个参数,并根据以下规则返回一个整数值: 如果o1小于o2,则返回负整数。 如果o1等于o2,则返回零。 如果o1大于o2,则返回正整数。 Comparator接口的使用: 在PriorityQueue的上下文中,Comparator用于定义队列中元素的排序规则。以下是如何使用Comparator来创建一个最大堆的例子: PriorityQueue<Long> q1 = new PriorityQueue<>(Comparator.reverseOrder()); 在这个例子中,Comparator.reverseOrder()是一个静态方法,它返回一个Comparator实例,该实例对实现了Comparable接口的对象的自然顺序进行反转。对于基本类型Long,这意味着队列将按照数值的降序排列,即队列头部将始终是最大的元素。 如果你想要定义一个自定义的排序规则,你可以创建一个实现了Comparator接口的匿名类或者使用lambda表达式,如下所示: // 使用匿名类 PriorityQueue<Long> q1 = new PriorityQueue<>(new Comparator<Long>() { @Override public int compare(Long o1, Long o2) { return o2.compareTo(o1); // 反转比较,实现最大堆 } }); // 使用lambda表达式 PriorityQueue<Long> q1 = new PriorityQueue<>((o1, o2) -> o2.compareTo(o1)); 在上述代码中,无论是使用匿名类还是lambda表达式,我们都定义了一个比较器,它将两个Long对象按照降序排列。 为什么使用Comparator? 使用Comparator的主要优势在于它的灵活性和可定制性。它允许你: 为没有实现Comparable接口的类定义排序规则。 为已经实现Comparable接口的类提供不同的排序规则。 在运行时动态地改变排序规则,而不必修改类的内部实现。 总之,Comparator接口是Java集合框架中一个强大的工具,它使得排序和搜索操作更加灵活和可定制。

  5. 数学运算

    • 使用Math.min函数来找出最小值。

 

相关文章:

  • 开源PDF解析工具olmOCR
  • 某个设备的RJ45网口接头为何不可连接任何POE设备
  • Qt 自带颜色属性
  • ZooKeeper分布式协调框架
  • 【LLM】DeepSeek开源技术汇总
  • 【Python】网络爬虫——词云wordcloud详细教程,爬取豆瓣最新评论并生成各式词云
  • 智能AI替代专家系统(ES)、决策支持系统(DSS)?
  • VScode 开发 Springboot 程序
  • StarRocks 在爱奇艺大数据场景的实践
  • 下载pyenv
  • 飞算 JavaAI:支持复杂业务逻辑生成,降低 80% 开发门槛
  • Zookeeper(80)Zookeeper的常见问题有哪些?
  • 机器幻觉产生的原因
  • IDEA相关配置
  • Vosk语音识别包
  • 运动想象 (MI) 分类学习系列 (17) : CCSM-FT
  • 大白话解释安全框架Spring Security是什么 有什么用 怎么用
  • Windows Qt开发到底选MSVC编译还是MinGW编译?
  • 小红书湖仓架构的跃迁之路
  • 004-利用Docker安装Mysql
  • 东莞网站建设服务公司/哈尔滨企业网站seo
  • 网站开发报价合同/北京关键词排名推广
  • 网站建设与推广策划书/最新军事新闻 今日 最新消息
  • 百度网站收录链接提交/网络营销成功案例
  • 为什么要建设公安公众服务网站/seo快速优化软件网站
  • 建设部网站企业资质/百度查重软件