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

版本说明

当前版本号[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;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DevChat:开发者专属的基于IDE插件化编程协助工具

DevChat&#xff1a;开发者专属的基于IDE插件化编程协助工具 一、DevChat 的介绍1.1 DevChat 简介1.2 DevChat 优势 二、DevChat 在 VSCode 上的使用2.1 安装 DevChat2.2 注册 DevChat2.3 使用 DevChat 三、DevChat 的实战四、总结 一、DevChat 的介绍 在AI浪潮的席卷下&#x…

国际化:i18n

什么是国际化&#xff1f; 国际化也称作i18n&#xff0c;其来源是英文单词 internationalization的首末字符和n&#xff0c;18为中间的字符数。由于软件发行可能面向多个国家&#xff0c;对于不同国家的用户&#xff0c;软件显示不同语言的过程就是国际化。通常来讲&#xff0…

【BMC】jsnbd介绍

jsnbd介绍 本文主要介绍一个名为jsnbd的开源项目&#xff0c;位于GitHub - openbmc/jsnbd&#xff0c;它实现了一个前端&#xff08;包含HTML和JS文件&#xff09;页面&#xff0c;作为存储服务器&#xff0c;可以指定存储内容&#xff1b;还包含一个后端的代理&#xff0c;这…

【chatglm3】(3):在AutoDL上,使用4090显卡,部署ChatGLM3API服务,并微调AdvertiseGen数据集,完成微调并测试成功!附视频演示。

在AutoDL上&#xff0c;使用4090显卡&#xff0c;部署ChatGLM3API服务&#xff0c;并微调AdvertiseGen数据集&#xff0c;完成微调并测试成功&#xff01; 其他chatgpt 和chatglm3 资料&#xff1a; https://blog.csdn.net/freewebsys/category_12270092.html 视频地址&#…

【C++入门篇】保姆级教程篇【下】

目录 一、运算符重载 1&#xff09;比较、赋值运算符重载 2&#xff09; 流插入留提取运算符重载 二、剩下的默认成员函数 1&#xff09;赋值运算符重载 2&#xff09;const成员函数 3&#xff09;取地址及const取地址操作符重载 三、再谈构造函数 1&#xff09;初始化列表 …

SparkSQL之Analyzed LogicalPlan生成过程

经过AstBuilder的处理&#xff0c;得到了Unresolved LogicalPlan。该逻辑算子树中未被解析的有UnresolvedRelation和UnresolvedAttribute两种对象。Analyzer所起到的主要作用就是将这两种节点或表达式解析成有类型的&#xff08;Typed&#xff09;对象。在此过程中&#xff0c;…

链表相关部分OJ题

&#x1f493;作者简介&#x1f44f;&#xff1a;在校大二迷茫大学生 &#x1f496;个人主页&#x1f389;&#xff1a;小李很执着 &#x1f497;系列专栏&#xff1a;Leetcode经典题 每日分享&#xff1a;人总是在离开一个地方后开始原谅它❣️❣️❣️———————————…

“第六十七天”

各位&#xff0c;昨天查找子串的方法想起来了&#xff0c;就是那个KMP算法......自己理解都有点困难&#xff0c;还看看能不能想一下&#xff0c;确实很困难啊。 不要忘了toupper函数和tolower函数不是直接改变字符的大小写&#xff0c;而是返回对应的大小写的值&#xff0c;需…

pytest-bdd快速示例和问题解决

BDD 与 pytest-bdd BDD 即 Behavior-driven development&#xff0c;行为驱动开发。BDD行为驱动是一种敏捷开发模式, 重点在于消除开发/测试对需求了解的歧义及用户场景的验证。 pytest-bdd 是一个BDD测试框架&#xff0c;类似于behave, cucumber。它可以统一单元测试和功能测…

【Git】第四篇:基本操作(理解工作区、暂存区、版本库)

Git 工作区、暂存区和版本库 工作区&#xff1a;就是我们创建的本地仓库所在的目录暂存区&#xff1a; stage或index&#xff0c;一般放在.git(可隐藏文件)目录下的index文件&#xff08;.git/index&#xff09;中&#xff0c;所以我们把暂存区有时候也叫做索引&#xff08;in…

飞书开发学习笔记(五)-Python快速开发网页应用

飞书开发学习笔记(五)-Python快速开发网页应用 一.下载示例代码 首先进入飞书开放平台: https://open.feishu.cn/app 凭证与基础信息 页面&#xff0c;在 应用凭证 中获取 App ID 和 App Secret 值。 教程和示例代码位置:https://open.feishu.cn/document/home/integrating-…

C语言 每日一题 牛客网 11.13 Day17

找零 Z国的货币系统包含面值1元、4元、16元、64元共计4种硬币&#xff0c;以及面值1024元的纸币。 现在小Y使用1024元的纸币购买了一件价值为N(0 < N≤1024)的商品&#xff0c;请问最少他会收到多少硬币&#xff1f; 思路 运用if语句进行判断分类 代码实现 int main() {…

基于php+thinkphp的网上书店购物商城系统

运行环境 开发语言&#xff1a;PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 系统主要分为管理员和用户二部分&#xff0c;管理员主要功能包括&#xff1a;首页、个人中心、用户管理、图书分类…

jupyter lab常用插件集合

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

毕业设计项目:基于java+springboot的共享单车信息网站

运行环境 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Ma…

【Java 进阶篇】JQuery DOM操作:通用属性操作的绝妙魔法

在前端的舞台上&#xff0c;JQuery犹如一位魔法师&#xff0c;为我们展现了操纵HTML元素的奇妙技巧。而在这个技巧的精妙组成中&#xff0c;通用属性操作是一门绝妙的魔法。在本篇博客中&#xff0c;我们将深入研究JQuery DOM操作中的通用属性操作&#xff0c;揭示这段魔法的神…

Linux进程间通信之命名管道及SystemV共享内存

命名管道及SystemV共享内存 命名管道1. 什么是命名管道2. 用命名管道实现server&client通信Log.hppcomm.hppserver.cppclient.cppclient.cppMakefile编译 system V共享内存1. 共享内存示意图2. 共享内存数据结构3. 共享内存函数3.1 shmget函数3.2 shmat函数3.3 shmdt函数3.…

一招验收测试自动化天下知

今天下午给同事就自动化验收测试做了一个简单的介绍&#xff0c;引起了大家的阵阵讨论。同时还有其他Team的人来分享各自的经验&#xff0c;他们也都做得相当不错。 测试包括很多种&#xff0c;单元测试、集成测试、功能测试、验收测试、数据库测试等等。撇开大家都熟悉的单元测…