CSDN每日一题学习训练——Java版(数据流的中位数、乘积最大子数组、旋转链表)

news2024/12/24 10:00:59

版本说明

当前版本号[20231113]。

版本修改说明
20231113初版

目录

文章目录

  • 版本说明
  • 目录
  • 数据流的中位数
    • 题目
    • 解题思路
    • 代码思路
    • 参考代码
  • 乘积最大子数组
    • 题目
    • 解题思路
    • 代码思路
    • 参考代码
  • 旋转链表
    • 题目
    • 解题思路
    • 代码思路
    • 参考代码

数据流的中位数

题目

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2

进阶:

如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

解题思路

  1. 使用两个优先队列(最小堆和最大堆)来存储数据。
  2. 初始化时,将最大堆作为较小的一半元素,最小堆作为较大的一半元素。
  3. 添加一个数字时,将其添加到最大堆中,然后将最大堆的顶部元素移动到最小堆中。这样可以保证最小堆的大小始终大于或等于最大堆的大小。
  4. 如果最小堆的大小大于最大堆的大小,将最小堆的顶部元素移动回最大堆中。这样可以保证两个堆的大小之差不超过1。
  5. 查找中位数时,如果两个堆的大小相等,则中位数为两个堆顶元素的平均值;否则,中位数为最大堆的顶部元素。

代码思路

  1. 在初始化时,创建了两个优先队列:minmaxmin是一个最小堆,用于存储较小的一半元素;max是一个最大堆,用于存储较大的一半元素。

       min = new PriorityQueue<>(); // 较小的一半元素队列
       max = new PriorityQueue<>((a, b) -> { // 较大的一半元素队列,按照降序排列
    
  2. addNum(int num)方法用于向数据结构中添加一个新的数字。首先,将数字添加到max堆中。然后,从max堆中移除顶部的元素,并将其添加到min堆中。这样可以确保min堆的大小始终大于或等于max堆的大小。如果min堆的大小比max堆的大小大,则将min堆中的顶部元素移除并添加到max堆中,以保持平衡。

     /**
         * 向数据结构中添加一个数字
         * @param num 要添加的数字
         */
        public void addNum(int num) {
            max.add(num); // 将数字添加到较大的一半元素队列中
            min.add(max.remove()); // 从较大的一半元素队列中取出最大值,并添加到较小的一半元素队列中
            // 如果较小的一半元素队列的大小大于较大的一半元素队列的大小,则将较小的一半元素队列中的最小值移动到较大的一半元素队列中
            if (min.size() > max.size()) {
                max.add(min.remove());
            }
        }
    
  3. findMedian()方法用于查找当前数据结构的中位数。如果max堆和min堆的大小相等,则中位数是两个堆顶元素的平均值;否则,中位数是max堆的顶部元素。

    /**
     * 查找当前数据结构的中位数
     * @return 中位数
     */
    public double findMedian() {
        // 如果两个队列的大小相等,则中位数为两个队列顶部元素的平均值
        if (max.size() == min.size()) {
            return (max.peek() + min.peek()) / 2.0;
        } else {
            // 否则,中位数为较大的一半元素队列的顶部元素
            return max.peek();
        }
    }

参考代码

这段代码是用于实现一个数据结构来查找中位数。该类使用两个优先队列**(最小堆和最大堆)**来实现这个功能。

class MedianFinder {
    PriorityQueue<Integer> min;
    PriorityQueue<Integer> max;
    /** initialize your data structure here. */
    public MedianFinder() {
        min = new PriorityQueue<>();
        max = new PriorityQueue<>((a, b) -> {
            return b - a;
        });
    }
    public void addNum(int num) {
        max.add(num);
        min.add(max.remove());
        if (min.size() > max.size())
            max.add(min.remove());
    }
    public double findMedian() {
        if (max.size() == min.size())
            return (max.peek() + min.peek()) / 2.0;
        else
            return max.peek();
    }
}
/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

乘积最大子数组

题目

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例 1:

输入: [2,3,-2,4]
输出:
6

解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

解题思路

解题思路如下:

  1. 初始化三个变量,max表示当前最大乘积,imax表示以当前元素结尾的最大乘积,imin表示以当前元素结尾的最小乘积。初始值都设为1,因为数组中至少有一个数字。
  2. 遍历数组中的每个元素,对于每个元素nums[i]:
    • 如果nums[i]小于0,说明负数乘以最大值会变成最小值,负数乘以最小值会变成最大值。所以交换imax和imin的值。
    • 更新imax为当前元素与imax的乘积和当前元素中的较大值。这样可以保证imax始终是当前子数组的最大乘积。
    • 更新imin为当前元素与imin的乘积和当前元素中的较小值。这样可以保证imin始终是当前子数组的最小乘积。
    • 更新max为当前最大乘积和imax中的较大值。这样可以保证max始终是整个数组的最大乘积。
  3. 遍历结束后,返回max作为结果。

代码思路

  1. 定义公共方法maxProduct,该方法接收一个整数数组nums作为参数,返回一个整数值。

  2. 在maxProduct方法中,初始化三个变量max、imax和imin,分别表示最大值、当前最大值和当前最小值。其中,max的初始值为Integer.MIN_VALUE,imax和imin的初始值为1。

    public int maxProduct(int[] nums) {
            int max = Integer.MIN_VALUE, imax = 1, imin = 1; // 初始化最大值为最小整数,imax和imin为1
    
  3. 使用for循环遍历整数数组nums,对于每个元素nums[i],执行以下操作:

    for (int i = 0; i < nums.length; i++)
    
    • 如果nums[i]小于0,说明当前元素为负数,需要交换imax和imin的值。

       if (nums[i] < 0) { // 如果当前元素为负数
                      int tmp = imax; // 交换imax和imin的值
                      imax = imin;
                      imin = tmp;
                  }
      
    • 更新imax为当前元素与imax的乘积和当前元素中的较大值。

           imax = Math.max(imax * nums[i], nums[i]); // 更新imax为当前元素与imax的乘积和当前元素中的较大值
      
    • 更新imin为当前元素与imin的乘积和当前元素中的较小值。

                  imin = Math.min(imin * nums[i], nums[i]); // 更新imin为当前元素与imin的乘积和当前元素中的较小值
      
    • 更新max为当前最大值和imax中的较大值。

       max = Math.max(max, imax); // 更新最大值为当前最大值和imax中的较大值
      
  4. 循环结束后,返回最大值max。

return max; // 返回最大值

参考代码

这段代码是用于求解一个整数数组中连续子数组的最大乘积

class Solution {
    public int maxProduct(int[] nums) {
        int max = Integer.MIN_VALUE, imax = 1, imin = 1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < 0) {
                int tmp = imax;
                imax = imin;
                imin = tmp;
            }
            imax = Math.max(imax * nums[i], nums[i]);
            imin = Math.min(imin * nums[i], nums[i]);
            max = Math.max(max, imax);
        }
        return max;
    }
}

旋转链表

题目

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

示例 1:

image-20231113221027303

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例 2:

image-20231113221152191

输入:head = [0,1,2], k = 4
输出:[2,0,1]

提示:

链表中节点的数目在范围 [0, 500] 内
-100 <= Node.val <= 100
0 <= k <= 2 * 109

解题思路

  1. 首先判断链表是否为空或者k是否为0,如果满足任一条件,则直接返回原链表。
  2. 初始化两个指针cursor和tail,分别指向链表的头节点和尾节点。同时记录链表的长度length。
  3. 遍历链表,找到尾节点tail,并让cursor指向头节点。
  4. 计算需要旋转的次数loop,即length减去k对length取模的结果。
  5. 将尾节点tail的next指针指向头节点head,完成链表的连接。
  6. 再次遍历链表,让cursor和tail分别向后移动loop次,直到cursor到达新的头节点。
  7. 将尾节点tail的next指针设置为null,断开循环连接。
  8. 返回新的头节点cursor。

代码思路

  1. 定义链表节点类ListNode,包含两个成员变量:val表示节点值,next表示指向下一个节点的指针。同时提供一个构造函数,用于初始化节点值。

    // 定义链表节点类
    public class ListNode {
        int val; // 节点值
        ListNode next; // 指向下一个节点的指针
        ListNode(int x) { // 构造函数,初始化节点值
            val = x;
        }
    }
    
  2. 定义解决方案类Solution,包含一个方法rotateRight,用于实现链表的右旋转操作。该方法接收两个参数:head表示链表的头节点,k表示需要旋转的次数。

    public ListNode rotateRight(ListNode head, int k)
    
  3. 在rotateRight方法中,首先判断链表是否为空或k是否为0,如果满足任一条件,则直接返回原链表。

      // 如果链表为空或k为0,直接返回原链表
            if (head == null || k == 0) {
                return head;
            }
    
  4. 定义游标cursor和尾节点tail,并初始化为null。

         // 定义游标和尾节点
            ListNode cursor = head;
            ListNode tail = null;
    
  5. 使用while循环遍历链表,计算链表的长度length。

     while (cursor.next != null) {
                cursor = cursor.next;
                length++;
            }
    
  6. 计算需要旋转的次数loop,即length减去k对length取模的结果。

      // 计算需要旋转的次数
            int loop = length - (k % length);
    
  7. 找到尾节点tail,并将其next指针指向头节点head,完成链表的连接。

     // 找到尾节点并连接头节点
            tail = cursor;
            cursor.next = head;
    
  8. 移动游标cursor到旋转位置,即头节点head。

     // 移动游标到旋转位置
            cursor = head;
    
  9. 使用for循环移动游标cursor和尾节点tail,直到游标cursor到达旋转位置。

      for (int i = 0; i < loop; i++) {
                cursor = cursor.next;
                tail = tail.next;
            }
    
  10. 断开循环连接,即将尾节点tail的next指针设置为null。

     // 断开循环连接,返回新的头节点
            tail.next = null;
    
  11. 返回新的头节点cursor。

       return cursor;
    

参考代码

这段代码是用于实现链表的右旋转操作

public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
    }
}
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || k == 0) {
            return head;
        }
        ListNode cursor = head;
        ListNode tail = null;
        int length = 1;
        while (cursor.next != null) {
            cursor = cursor.next;
            length++;
        }
        int loop = length - (k % length);
        tail = cursor;
        cursor.next = head;
        cursor = head;
        for (int i = 0; i < loop; i++) {
            cursor = cursor.next;
            tail = tail.next;
        }
        tail.next = null;
        return cursor;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1204950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPSS时间序列模型预测

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件请点击此链接下…

Leetcode刷题详解——解数独

1. 题目链接&#xff1a;37. 解数独 2. 题目描述&#xff1a; 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能…

Vue基础之组件通信(二)

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

ROS基础—话题通信的执行

1、打开终端启动roscore 2、手动添加命令到.bashrc Ⅰ.切换到home目录下&#xff0c;按Ctrlh显示隐藏的文件夹&#xff0c;找到并打开./bashrc。 Ⅱ.在./bashrc最后一行添加命令: # xxx是你工作空间的名称 source ~/xxx/devel/setup.bash 之后保存.bashrc文件即可。 这样子…

IMU识别实验鼠的运动轨迹

临床前通常要做小鼠行为试验。然而&#xff0c;研究人员在观察和分析其行为和反应上往往需要耗费大量时间。针对这种情况&#xff0c;结合目前IMU的飞速发展&#xff0c;香港的研究员们构思了一种基于惯性测量单元&#xff08;IMU&#xff09;的传感器&#xff0c;用于捕获实验…

保姆级vue-pdf的使用过程

第一步 引入vue-pdf npm install --save vue-pdf 第二步 按照需求我们慢慢进行 01.给你一个pdf文件的url&#xff0c;需要在页面渲染 代码 <template><div><pdfref"pdf":src"url"></pdf></div> </template> <…

vue3 setup() 高级用法

文章目录 前言一、选项式API 和 组合式API 区别用一张图告诉你它们的区别&#xff1a; 二、setup 具体怎么用&#xff1f;2.1、setup 什么时候执行&#xff1f;2.2、setup 数据和方法如何使用&#xff1f;2.3、setup 内部有 this 吗&#xff1f;2.4、setup 内钩子函数如何使用&…

SDL2 播放视频数据(YUV420P)

1.简介 这里以常用的视频原始数据YUV420P为例&#xff0c;展示视频的播放。 SDL播放视频的流程如下&#xff1a; 初始化SDL&#xff1a;SDL_Init();创建窗口&#xff1a;SDL_CreateWindow();创建渲染器&#xff1a;SDL_CreateRenderer();创建纹理&#xff1a;SDL_CreateText…

vivado产生报告阅读分析-常规报告2

1、Report I/O “ I/O Report ” &#xff08; I/O 报告 &#xff09; 用于替代 AMD ISE Design Suite PAD 文件。“ I/O Report ”可列出 &#xff1a; • “ Pin Number ” &#xff08; 管脚编号 &#xff09;&#xff1a; 表示器件中的所有管脚 • “ Signal Name ” …

vue3配置@别名

在项目开发中&#xff0c;通常我们是不写相对路径的&#xff0c;因为有些文件需要在不同的文件中使用&#xff0c;如果使用相对路径&#xff0c;那么我们每次去CV路径的时候就要重新修改。因此通常我们是写跟路径的&#xff0c;但是从头开始又太过于麻烦&#xff0c;因此我们使…

ChatGLM3本地部署运行(入门体验级)

文章目录 前言零 硬件小白基知填坑eForce Game Ready驱动程序CUDA常用命令 环境准备NVIDIA驱动更新CUDA安装 部署补充内容体验 前言 学习自B站up主技术爬爬虾&#xff0c;感谢up主提供的整合包&#xff01; 零 硬件 6GB以上显存的NVIDIA显卡&#xff08;品质越高&#xff0c…

22.斐波那契数列数列前20项.

#include<stdio.h>int main(){int i,sum1; int a[100];a[0]0;a[1]1;for(i2;i<20;i){a[i]a[i-1]a[i-2]; sumsuma[i];}printf("斐波那契数列的前20项和为&#xff1a;%d",sum);return 0;}

沧州市壹家人社工小赵庄乡社工站常态化开展关爱一老一小活动

沧州市壹家人社会工作服务中心承接新华区小赵庄乡社工站以来以服务一老一小为工作重点&#xff0c;发挥五社联动的重要作用&#xff0c;开展“幸福院”和“护蕾驿站”两个微项目&#xff0c;聚焦需求&#xff0c;采取社工引领志愿服务的模式&#xff0c;常态化为老人和孩子开展…

Wpf 使用 Prism 实战开发Day05

首页设计 1.效果图 一.代码现实 根据页面布局&#xff0c;可以将页面设计成3行&#xff0c;每行中分多少列&#xff0c;看需求而定根据页面内容&#xff0c;设计Model 实体类&#xff0c;以及View Model 1.Index.xaml 页面布局设计 RowDefinition 分行&#xff08;Row&#xf…

【LeetCode】每日一题 2023_11_12 每日一题 Range 模块(线段树)

文章目录 刷题前唠嗑题目&#xff1a;Range 模块题目描述代码与解题思路 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 嗯&#xff1f;怎么是 hard&#xff0c;好长&#xff0c;可恶&#xff0c;看不懂&#xff0c;怎么办 题目&#xff1a;Range 模块 题…

mindspore mindyolo目标检测华为昇腾上推理使用

参考&#xff1a; https://github.com/mindspore-lab/mindyolo 使用案例&#xff1a; https://github.com/mindspore-lab/mindyolo/blob/master/GETTING_STARTED.md 安装&#xff1a; pip install mindyolo特别注意opencv-python、opencv-python-headless版本问题&#xff0…

深入理解C++关联式容器:set、multiset、map和multimap详解

序列式容器 与 关联式容器 我们知道&#xff1a; C 中&#xff0c;我们将 vector、list、queue 这种底层为线性序列的数据结构叫做 序列式容器&#xff0c;其存储的就是元素本身。而 关联式容器 以键-值对的形式存储数据。每个键在容器中必须是唯一的&#xff0c;而值则与相应…

基于连续Hopfield神经网络优化——旅行商问题优化计算

大家好&#xff0c;我是带我去滑雪&#xff01; 利用神经网络解决组合优化问题是神经网络应用的一个重要方面。所谓组合优化问题&#xff0c;就是在给定约束条件下&#xff0c;使目标函数极小&#xff08;或极大&#xff09;的变量组合问题。将Hopfield网络应用于求解组合优化问…

Centos7 升级到 Centos8 教程以及关于dnf包管理工具的若干问题解决方案

目录 为什么升级一、参考文档二、升级步骤三、安装git编码错误缓存问题安装git依赖冲突问题解决办法 为什么升级 jenkins 2.4版本需要CentOS8 一、参考文档 点我 二、升级步骤 1.安装epel源 yum -y install epel-release2.安装rpmconf和yum-utils yum -y install rpmco…

死锁(JAVA)

死锁在多线程代码中是非常严重的BUG&#xff0c;一旦代码中出现死锁就会导致线程卡死。 当单个线程连续两次对同一个对象进行加锁操作时&#xff0c;如果该锁是不可重入锁就会发生死锁&#xff08;线程卡死&#xff09; 两个线程两把锁&#xff0c;如果出现这种情况也是会发生…