华为OD机考算法题:生日礼物

news2024/11/19 19:42:54

题目部分

题目生日礼物
难度
题目说明小牛的孩子生日快要到了,他打算给孩子买蛋糕和小礼物,蛋糕和小礼物各买一个,他的预算不超过x元。蛋糕 cake 和小礼物 gift 都有多种价位的可供选择。
输入描述第一行表示cake的单价,以逗号分隔。
第二行表示gift的单价,以逗号分隔。
第三行表示 x 预算。
输出描述输出数字表示购买方案的总数。
补充说明1 ≤ cake.length ≤ 10^{5}
1 ≤ gift.length ≤10^{5}
1 ≤ cake[], gift[] ≤ 10^{5}
1 ≤ X ≤2 * 10^{5}
------------------------------------------------------
示例
示例1
输入10,20,5
5,5,2
15
输出6
说明小牛有6种购买方案,所选蛋糕与所选礼物在数组中对应的下标分别是:
第1种方案: cake[0]+ gift[0] = 10 + 5 = 15;
第2种方案: cake[0]+ gift[1] = 10 + 5 = 15;
第3种方案: cake[0]+ gift[2] = 10 + 2 = 12;
第4种方案: cake[2]+ gift[0] = 5 + 5 = 10;
第5种方案: cake[2]+ gift[1] = 5 + 5 = 10;
第6种方案: cake[2]+ gift[2] = 5 + 2 = 7。


解读与分析

题目解读

给定 2 组数据,在两组数据中各取 1 个,使 2 个数字之和不高于指定值 x。

分析与思路

如果逐个遍历两组数字中每一种组合,时间复杂度为 O(n^{2})。由于 cake、gift 的最大长度为 10^{5},当它们长度较大时,性能会变得很差,我们有更好的方法。

实现如下:
1. 对 cake、gift 进行排序,从大到小。
2. 对 cake 进行二分查找,从 cake 中找到值小于 x 的最大值所对应的下标,设为 minCake。此时,计算出cake 中可能买的 cake 下标范围是 [ minCake, cake.length - 1]。对处于下标范围的 cake 遍历(假设当前正遍历到的下标为 i),进行步骤 3 操作。
3. 如步骤 2,假设当前的 cake 是 cake[i],那么所能购买的 gift 最大价格为 x - cake[i],设为 giftMaxValue。使用二分查找,找到价格不高于 giftMaxValue 的最大值,设下标为 j,那么 gift 的下标可选范围是 [ j, gift.length -1 ]。即意味着当选择 cake[i] 时,gift 的可选个数是 gift.length - j。
4. 继续遍历下一个 cake,即下一个 i,如步骤 3 中,重新计算 giftMaxValue,此时的 giftMaxValue 一定大于前一个计算出来的 giftMaxValue,即意味着这一轮中 gift 下标的 j 的范围一定在 0 和上一轮计算出来的 j 之间,对 [ 0, 上一轮计算的 j ] 进行二分查找,找到不大于 giftMaxValue 的最大值(即最下小标),即计算出选择当前 cake 时,gift 的可选个数。
5. 继续进行步骤 4,直至遍历完所有的 cake,最终所有可选个数之和,即为购买方案总数。

这种方案的时间复杂度为O(nlogn),空间复杂度O(n)。


代码实现

Java代码

import java.util.Arrays;
import java.util.Scanner;
import java.util.Comparator;

/**
 * 生日礼物
 * 
 * @since 2023.10.31
 * @version 0.1
 * @author Frank
 *
 */
public class BirthdayGift {

    public static void main(String[] args) {
	Scanner sc = new Scanner(System.in);
	while (sc.hasNext()) {
	    String input = sc.nextLine();
	    String[] strNumber = input.split(",");
	    Integer[] cakes = new Integer[strNumber.length];
	    for (int i = 0; i < strNumber.length; i++) {
		cakes[i] = Integer.parseInt(strNumber[i]);
	    }

	    input = sc.nextLine();
	    strNumber = input.split(",");
	    Integer[] gifts = new Integer[strNumber.length];
	    for (int i = 0; i < strNumber.length; i++) {
		gifts[i] = Integer.parseInt(strNumber[i]);
	    }

	    input = sc.nextLine();
	    int x = Integer.parseInt(input);
	    processBirthdayGift(cakes, gifts, x);
	}
    }

    private static void processBirthdayGift(Integer[] cakes, Integer[] gifts, int x) {	
	// 从大到小排序
	Comparator<Integer> comp = new Comparator<Integer>() {
	    @Override
	    public int compare(Integer o1, Integer o2) {
		return o2 - o1;
	    }
	    
	};
	Arrays.sort( cakes, comp );
	Arrays.sort( gifts, comp );
	
	int cakesFromIndex = findMaxValueIndex( x - 1, cakes.length - 1, cakes );
	int sum = 0;
	int highIndex = gifts.length - 1;
	for( int i = cakesFromIndex; i < cakes.length; i ++ )
	{
	    int giftMaxValue = x - cakes[i];
	    highIndex = findMaxValueIndex( giftMaxValue, highIndex, gifts );
	    sum += ( gifts.length - highIndex ) ;
	}	
	System.out.println( sum );
    }
    
    private static int findMaxValueIndex( int maxValue, int highIndex, Integer[] srcArr )
    {
	// 已排序从大到小的数组,取值范围在 [0, fromIndex]
	int low = 0;
	int high = highIndex;
	int mid = ( low + high ) / 2;
	while( low <= high )
	{
	    mid = ( low + high ) / 2;
	    if( maxValue == srcArr[mid] )
	    {
		// 相等,还需判断所有相等的情况
		while( mid >= 1 && srcArr[mid - 1 ] == srcArr[mid])
		{
		    mid --;
		}
		return mid;
	    }else if( maxValue > srcArr[mid] )
	    {
		high = mid - 1;
	    }else
	    {
		low = mid + 1;
	    }
	}
	
	// 此时 low > high
	if( high < 0 )
	{
	    return 0;
	}
	if( srcArr[ high ] < maxValue )
	{
	    return high;
	}
	if( srcArr[low] < maxValue )
	{
	    return low;
	}
	if( low + 1 <= srcArr.length -1 )
	{
	    return low + 1;
	}else
	{
	    return srcArr.length -1;
	}
	
	
    }
}

JavaScript代码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function() {
    while (line = await readline()) {

        var strNumber = line.split(",");
        var cakes = new Array();
        for (var i = 0; i < strNumber.length; i++) {
            cakes[i] = parseInt(strNumber[i]);
        }

        line = await readline();
        var strNumber = line.split(",");
        var gifts = new Array();
        for (var i = 0; i < strNumber.length; i++) {
            gifts[i] = parseInt(strNumber[i]);
        }

        line = await readline();
        var x = parseInt(line);
        processBirthdayGift(cakes, gifts, x);

    }
}();

function processBirthdayGift(cakes, gifts, x) {
    // 从大到小排序
    var comp = function( a, b) {
        return b - a;        
    };
    cakes.sort( comp );
    gifts.sort( comp );

    var cakesFromIndex = findMaxValueIndex( x - 1, cakes.length - 1, cakes );
    var sum = 0;
    var highIndex = gifts.length - 1;

    for( var i = cakesFromIndex; i < cakes.length; i ++ )
    {
        var giftMaxValue = x - cakes[i];
        highIndex = findMaxValueIndex( giftMaxValue, highIndex, gifts );
        sum += ( gifts.length - highIndex ) ;
    }   
    console.log( sum );
}

function findMaxValueIndex(maxValue, highIndex, srcArr) {
    // 已排序从大到小的数组,取值范围在 [0, fromIndex]
    var low = 0;
    var high = highIndex;
    var mid = parseInt( (low + high) / 2 );
    while (low <= high) {
        mid = parseInt( (low + high) / 2 );
        if (maxValue == srcArr[mid]) {
            // 相等,还需判断所有相等的情况
            while (mid >= 1 && srcArr[mid - 1] == srcArr[mid]) {
                mid--;
            }
            return mid;
        } else if (maxValue > srcArr[mid]) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    // 此时 low > high
    if (high < 0) {
        return 0;
    }
    if (srcArr[high] < maxValue) {
        return high;
    }
    if (srcArr[low] < maxValue) {
        return low;
    }
    // should never come here
    if (low + 1 <= srcArr.length - 1) {
        return low + 1;
    } else {
        return srcArr.length - 1;
    }
}

(完)

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

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

相关文章

③ 软件工程CMM、CMMI模型【软考中级-软件设计师 考点】

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ ③ 软件工程CMM、CMMI模型【软考中级-软件设计…

SpringCloud Alibaba Demo(Nacos,OpenFeign,Gatway,Sentinel)

开源地址&#xff1a; ma/springcloud-alibaba-demo 简介 参考&#xff1a;https://www.cnblogs.com/zys2019/p/12682628.html SpringBoot、SpringCloud 、SpringCloud Alibaba 以及各种组件存在版本对应关系。可参考下面 版本对应 项目前期准备 启动nacos. ./startup.c…

营收净利双降、股价下跌四成,敷尔佳带伤闯关“双11”

今年双11预售已经开启&#xff0c;敷尔佳在天猫、抖音等电商平台火热营销&#xff1b;营销热业绩冷&#xff0c;敷尔佳的三季报不及预期。 10月23日&#xff0c;哈尔滨敷尔佳科技发展有限公司(下称“敷尔佳”&#xff0c;301371SZ)公布2023年三季报&#xff0c;其三季度营收净…

【C++ 系列文章 -- 程序员考试 下午场 C++ 专题 201805 】

文章目录 1.1 C 题目六1.1.1 填空&#xff08;1&#xff09;详解1.1.1.1 C 纯虚函数介绍 1.1.2 填空&#xff08;2&#xff09;详解1.1.2.1 父类声明了带参构造函数1.1.2.2 子类中构造函数的构造原则 1.1.3 填空&#xff08;3&#xff09;详解1.1.4 填空&#xff08;4&#xff…

Python小试牛刀:GUI(图形界面)实现计算器界面

Python GUI 是指 Python 图形用户界面库&#xff0c;它们可以帮助开发者创建在计算机上运行的图形用户界面&#xff08;GUI&#xff09;。下面是一些常用的 Python GUI 库&#xff1a; Tkinter&#xff1a; Tkinter 是 Python 的标准 GUI 库&#xff0c;它是一个开源的、跨平台…

LeetCode刷题之 存在重复元素(题目分析➕源代码)

题目链接&#x1f517;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 1. 题目分析 本题是要找到数组中的重复元素&#xff0c;所以我们分析出一下几点&#xff1a; 1. bool是一种数据类型&#xff0c;true是非0值&#xff0c;false是0.。 2. 数组…

绘制教材P68页产品的层次方框图。

层次方框图&#xff1a; 用树形结构的一系列多层次的矩形框绘制数据的层次结构&#xff0c;树形结构的顶层是一个单独的矩形框&#xff0c;它代表完整的数据结构&#xff0c;下面的各层矩形框代表这个数据的子集&#xff0c;最底层的各个框代表组成这个数据的实际数据元素&…

verilog语言学习

1. 时延 2. 一位全加器设计&#xff1a;三种建模方式 实际的设计中往往是这三种设计模式的混合 3. 4. 5. 6. 7. 建立模型时信号的连接&#xff08;重点&#xff09; 8. initial语句 9. always语句 在always中不能同时判断同一个信号的上升沿&#xff08;posedge&#xff0…

网工内推 | IDC网工、运维,上市公司,主流厂商认证优先,六险一金

01 软通动力 招聘岗位&#xff1a;ICD机房运维工程师 职责描述&#xff1a; 1.维护及管理数据中心内各类服务器及网络设备。 2.处理数据中心各类服务器和网络相关故障和告警。 3.负责数据中心内项目交付管理&#xff0c;包括LLD评审、硬装工艺验收、ASP施工管理等。 4.负责数据…

什么是互动广告

随着数字技术的迅速发展和消费者行为的转变&#xff0c;互动广告已成为现代广告行业的重要组成部分。互动广告以其独特的优势和形式&#xff0c;不断刷新人们对广告的认知&#xff0c;为广告行业带来新的机遇和挑战&#xff0c;那么就来一起了解互动广告吧。 一、互动广告的定义…

笔记49:53语言模型--课程笔记

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\3.循环神经网络\语言模型 PS&#xff1a;沐神别怪我&#xff0c;实在是截屏避不开啊&#xff0c;我就留个备忘&#xff0c;在我博客里先委屈一下哈&#xff0c;对不住了 a a a a a a a a a a…

二十一、Arcpy批量镶嵌——结合Landsat数据提取城市建成区

一、前言 前文介绍Pycharm软件安装和激活,以及运行环境的设置,本文就详细介绍一下几何Landsat数据有哪些步骤可以通过Arcpy代码来实现批量操作,其实主要集中在Landsat数据预处理过程中,包括数据镶嵌、裁剪、去背景、重采样以及波段组合计算、NDVI、NDBI计算,在一定程度上…

JetBrains TeamCity远程命令执行漏洞

一、免责声明&#xff1a; 本次文章仅限个人学习使用&#xff0c;如有非法用途均与作者无关&#xff0c;且行且珍惜&#xff1b;由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;公众号望雪阁及作者不为此承…

EPLAN连接编号的问题

连接编号的问题 1.连接编号的目的 连接编号也就是常说的编线号.编线号的目的是为了在现场装配,调试,检修的时候,方便查线.使真实的接线与原理图能够方便地对应. 2.标准对连接编号的规定 标准中规定了导线应该编线号,但是没有说一定要使用什么样的规则.我觉得保证正常使用的前提…

YOLOv8改进: AIFI (尺度内特征交互)助力YOLO | YOLO终结者?RT-DETR一探究竟

💡💡💡本文全网首发独家改进: AIFI (尺度内特征交互)助力YOLO ,提升尺度内和尺度间特征交互能力,同时降低多个尺度的特征之间进行注意力运算,计算消耗较大等问题 推荐指数:五星 AIFI | 亲测在多个数据集能够实现涨点 💡💡💡Yolov8魔术师,独家首发创新(…

unordered系列关联式容器--哈希结构详细讲解及使用示例

目录 unordered系列关联式容器unordered_map 哈希哈希概念哈希函数直接定址法&#xff1a;除留余数法&#xff1a; 哈希冲突解决哈希冲突闭散列&#xff1a;开散列&#xff1a; unordered系列关联式容器 之前讲解在C98中STL提供了底层为红黑树结构的一系列关联式容器&#xff…

基于动物迁徙算法的无人机航迹规划-附代码

基于动物迁徙算法的无人机航迹规划 文章目录 基于动物迁徙算法的无人机航迹规划1.动物迁徙搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用动物迁徙算法来优化无人机航迹规划。 …

Django实战项目-学习任务系统-用户管理

接着上期代码框架&#xff0c;开发第6个功能&#xff0c;用户管理&#xff0c;查看用户信息和学生用户属性值&#xff0c;尤其是总积分值&#xff0c;还可以查看积分流水明细&#xff0c;完成任务奖励积分&#xff0c;兑换物品消耗积分。 第一步&#xff1a;编写第6个功能-用户…

ChatGPT 3.5只有200亿规模的参数?最新微软的论文暴漏OpenAI的ChatGPT的参数规模远低于1750亿!

本文来自DataLearnerAI官方网站&#xff1a;ChatGPT 3.5只有200亿规模的参数&#xff1f;最新微软的论文暴漏OpenAI的ChatGPT的参数规模远低于1750亿&#xff01; | 数据学习者官方网站(Datalearner)https://www.datalearner.com/blog/1051698672594665 2022年11月底发布的Cha…