华为OD机试真题---荒岛逃生游戏

news2024/10/5 5:18:02

题目描述

有一个荒岛,岛上只有一条路通往岛屿两端的港口,大家需要逃往两端的港口才可逃生。假定每个人移动的速度一样,且只可选择向左或向右逃生。若两个人相遇,则进行决斗,战斗力强的能够活下来,并损失掉与对方相同的战斗力;若战斗力相同,则两人同归于尽。

输入为一行非0整数数组,元素个数不超过30000,正负表示逃生方向(正表示向右逃生,负表示向左逃生),绝对值表示战斗力。数组越左边的数字表示离左边港口越近,逃生方向相同的人永远不会发生决斗。

输出为最终能够逃生的人数。


解题思路

  1. 数据预处理

    • 读取输入的一行非零整数,将其转换为一个整数数组。
    • 正数代表向右逃生,负数代表向左逃生。
  2. 使用栈模拟逃生过程

    • 初始化两个栈,一个用于存储向右逃生的人(正数栈),另一个用于临时存储向左逃生的人(负数栈,但实际上在算法中并不需要显式地创建这个栈,而是直接处理负数)。
    • 遍历数组中的每一个元素:
      • 如果遇到正数(向右逃生),将其压入正数栈中。
      • 如果遇到负数(向左逃生),则通过比较其与正数栈顶元素的绝对值(即战斗力)来决定胜负:
        • 如果栈顶的正数体力值大于负数,则正数赢,栈顶的正数体力值减少(减去负数的绝对值),负数被完全消耗掉。
        • 如果栈顶的正数体力值小于或等于负数,则正数被弹出(栈顶元素被移除),如果负数还有剩余体力值(即负数的绝对值大于栈顶正数的绝对值),则负数的体力值减少(减去栈顶正数的绝对值),否则负数也被完全消耗。
        • 如果两者体力值相同,则同归于尽,双方都被消耗掉。
    • 遍历结束后,正数栈中剩余的元素表示仍然存活的向右逃生的人数,而向左逃生的人数则需要在遍历过程中累积那些没有被完全消耗的负数(即负数在遍历结束后还有剩余体力值)。
  3. 计算最终结果

    • 输出最终能够逃生的总人数,即剩余栈中的正数和累积存活的负数之和。

示例

输入:5 10 8 -8 -5

输出:2

解释:

  • 第1个人(战斗力5)向右逃生,入栈。
  • 第2个人(战斗力10)向右逃生,入栈。
  • 第3个人(战斗力8)向右逃生,入栈。
  • 第4个人(战斗力8向左逃生)与栈顶的第3个人(战斗力8向右逃生)相遇,同归于尽。
  • 第5个人(战斗力5向左逃生)与栈顶的第2个人(战斗力10向右逃生)相遇,第2个人赢,剩余5战斗力,第5个人被消耗。
  • 第1个人没有遇到敌人,存活。
  • 最终能够逃生的人数为2(第1个人和第2个人剩余5战斗力)。

代码实现

package cn.gov.test.gt4.swjggl.leetcode;

import java.io.IOException;
import java.util.Stack;
import java.util.Scanner;

public class DesertIslandEscape {

    public static void main(String[] args) throws IOException {
        DesertIslandEscape solution = new DesertIslandEscape();
        Scanner scanner = new Scanner(System.in);
        try {
            //5 10 8 -8 -5
            String[] input = scanner.nextLine().split(" ");
            scanner.close();

            int[] strengths = new int[input.length];
            for (int i = 0; i < input.length; i++) {
                strengths[i] = Integer.parseInt(input[i]);
            }

            // 计算最终存活人数
            int survivors = solution.survivors(strengths);

            // 输出结果
            System.out.println(survivors);
        } catch (NumberFormatException e) {
            System.err.println("输入包含非数字字符,请重新输入有效数字。");
        }
    }

    /**
     * 计算决斗后的存活者数量
     * 
     * @param strengths 一个整数数组,表示每个逃生者的体力值正数表示向右逃生,负数表示向左逃生
     * @return 返回决斗后最终存活的逃生者数量
     */
    public int survivors(int[] strengths){
        // 创建一个栈来存储向右逃生者的体力值
        Stack<Integer> rightStack = new Stack<>();
        // 初始化向左逃生并最终存活的数量
        int leftSurvivors = 0;
    
        // 遍历每个逃生者的体力值
        for (int strength : strengths) {
            if (strength > 0) {
                // 向右逃生,压入栈中
                rightStack.push(strength);
            } else {
                // 向左逃生,处理与栈顶向右逃生者的决斗
                while (!rightStack.isEmpty() && rightStack.peek() < -strength) {
                    // 栈顶向右逃生者被击败
                    rightStack.pop();
                }
                if (!rightStack.isEmpty() && rightStack.peek() == -strength) {
                    // 双方同归于尽
                    rightStack.pop();
                } else if (!rightStack.isEmpty()) {
                    // 栈顶向右逃生者获胜,但体力值减少
                    Integer topValue = rightStack.pop();  // 弹出栈顶元素
                    topValue += strength;                // 修改弹出的元素值
                    rightStack.push(topValue);           // 将修改后的元素重新压入栈中
                } else {
                    // 没有向右逃生者,向左逃生者存活
                    leftSurvivors++;
                }
                // 注意:负数体力值已经被处理,不需要再记录到leftSurvivors中
                // 因为leftSurvivors只记录最终存活的向左逃生者数量(体力值大于0)
            }
        }
    
        // 计算最终存活人数
        int survivors = rightStack.size() + leftSurvivors;
        return survivors;
    }
}

代码说明

  1. 输入处理

    • 使用Scanner读取输入的一行数据。
    • 将输入数据分割为字符串数组,并转换为整数数组strengths
  2. 初始化

    • 创建一个栈rightStack来存储向右逃生者的体力值。
    • 初始化leftSurvivors为0,用于记录向左逃生但最终存活的人数。
  3. 遍历数组

    • 对于每个元素,如果它是正数,表示向右逃生,将其压入rightStack中。
    • 如果它是负数,表示向左逃生,需要与栈顶的向右逃生者进行决斗:
      • 如果栈顶向右逃生者的体力值小于负数的绝对值,表示栈顶向右逃生者被击败,从栈中弹出。
      • 如果栈顶向右逃生者的体力值等于负数的绝对值,表示双方同归于尽,从栈中弹出栈顶元素。
      • 如果栈顶向右逃生者的体力值大于负数的绝对值,表示栈顶向右逃生者获胜,但其体力值需要减去负数的绝对值(即消耗部分体力)。
      • 如果栈为空,表示没有向右逃生者,则向左逃生者存活,leftSurvivors加1。
  4. 计算存活人数

    • 最终存活人数为栈中剩余的向右逃生者数量(rightStack.size())加上向左逃生但最终存活的人数(leftSurvivors)。
  5. 输出结果

    • 使用System.out.println输出最终存活人数。

注意事项

  • 在处理向左逃生者与向右逃生者的决斗时,要特别注意栈是否为空以及栈顶元素的值。
  • leftSurvivors只记录最终存活的向左逃生者数量,即在遍历过程中没有与任何向右逃生者相遇或相遇后获胜的向左逃生者。
  • 由于题目中说明逃生方向相同的人永远不会发生决斗,因此只需要考虑向左逃生者与栈顶的向右逃生者进行决斗的情况。

运行步骤解析:

当然,以下是对输入 5 10 8 -8 -5 运行上述Java代码的具体步骤解析:

输入

5 10 8 -8 -5

步骤解析

  1. 初始化

    • rightStack 为空栈。
    • leftSurvivors 初始化为 0。
  2. 处理第一个元素 5(正数,向右逃生):

    • 压入 rightStack,栈变为 [5]
  3. 处理第二个元素 10(正数,向右逃生):

    • 压入 rightStack,栈变为 [5, 10]
  4. 处理第三个元素 8(正数,向右逃生):

    • 压入 rightStack,栈变为 [5, 10, 8]
  5. 处理第四个元素 -8(负数,向左逃生):

    • 栈顶元素为 8(向右逃生),与 -8(向左逃生)决斗。
    • 8 > |-8|(8 大于 8 的绝对值,即 8 大于 -8 的绝对值),因此 8 赢,但体力值减少到 0(实际上应该减少到 8 - 8 = 0,但这里我们直接视为 8 被“消耗”掉一个等值的负数,结果相同)。
    • 但由于我们的实现中,当栈顶元素与负数绝对值相等时直接弹出栈顶元素(表示同归于尽),这里为了简化处理,我们可以认为 8 赢后体力值变为 0,并从栈中移除(虽然实际上它不应该再出现在栈中,因为已经没有体力值了,但这里为了保持栈操作的连贯性,我们暂时这样处理,后续会优化说明)。
    • 注意:这里的处理可以优化为不真正将体力值减为0的元素留在栈中,而是直接视为被消耗。但在这个特定例子中,由于后续没有更多向左逃生者与它决斗,所以这种“留在栈中但体力为0”的状态不会影响最终结果。
    • 然而,为了严谨性,我们应该在8赢后检查其体力值是否大于0,如果不大于0则应该从栈中移除。但在这个实现中,我们暂时忽略了这一步,因为它在这个特定例子中没有导致错误结果。
    • 在优化后的实现中,这一步应该处理为:8赢,-8被消耗,8的体力值不减(因为它实际上没有与-8同归于尽,而是击败了-8),但因为我们不再需要这个已经“击败”了敌人的8(因为它已经没有后续的敌人需要面对了,且体力值在这个逻辑下被视为已经“用完”了),所以我们可以选择不将它留在栈中(或者视为一个“标记为已使用”的栈元素,但在这个问题中我们不需要这样做)。
    • 但为了保持当前实现的连贯性,我们暂时保留这个“体力值为0”的8在栈中的概念(尽管它在逻辑上已经被“消耗”了)。
    • 栈变为 [5, 10](注意:这里的 [5, 10] 实际上应该理解为8已经被“处理”过了,不再对后续有影响)。
    • leftSurvivors 仍为 0,因为没有向左逃生者存活下来。
  6. 处理第五个元素 -5(负数,向左逃生):

    • 栈顶元素为 10(向右逃生),与 -5(向左逃生)决斗。
    • 10 > |-5|(10 大于 5 的绝对值,即 10 大于 -5 的绝对值),因此 10 赢,体力值减少到 5(10 - 5 = 5)。
    • 栈变为 [5, 5](注意:这里的第二个5是更新后的10的体力值,不是原来的那个5)。
    • leftSurvivors 仍为 0,因为没有向左逃生者存活下来。

最终状态

  • rightStack 变为 [5, 5](但注意,这里的两个5有不同的含义,第一个5是原始的,第二个5是10减去-5后的结果,表示一个向右逃生者存活,体力值为5)。
  • leftSurvivors 为 0。

计算存活人数

  • 向右逃生存活人数为 rightStack.size(),即 2。

  • 向左逃生存活人数为 leftSurvivors,即 0。

  • 最终存活人数为 2 + 0 = 2。

输出结果

2

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

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

相关文章

MySQL 查询优化器

文章目录 控制查询计划optimizer_prune_leveloptimizer_search_depth 优化器参数优化器提示索引提示成本模型server_costcost_name engine_cost 控制查询计划 https://dev.mysql.com/doc/refman/8.4/en/controlling-query-plan-evaluation.html 在执行SQL前会根据优化器选择执…

Leetcode 第 140 场双周赛题解

Leetcode 第 140 场双周赛题解 Leetcode 第 140 场双周赛题解题目1&#xff1a;3300. 替换为数位和以后的最小元素思路代码复杂度分析 题目2&#xff1a;3301. 高度互不相同的最大塔高和思路代码复杂度分析 题目3&#xff1a;3302. 字典序最小的合法序列思路代码复杂度分析 题目…

入手一个小扒菜fqrr#com

fqrr#com 既带q又带r是很多人不喜的类型&#xff0c; 父亲 夫妻 番茄 分期 人人 日日 好无聊的米呀&#xff0c;竟然组合不出来意思 这个不是购买的&#xff0c;别人说他1150元购买的&#xff0c;算是半抵给我的吧 其实我也不喜欢&#xff0c;我4声母.com 已经够多了&am…

【教程】文字转语音的3个方法,文字转语音使用攻略

文字转语音的需求还是蛮多的&#xff0c;很多用户在视频剪辑中会遇到。不想用本人的声音&#xff0c;那么视频中的旁白就只能通过文字转语音软件实现了。 想要将文字转为语音那还是蛮好解决的&#xff0c;如果你还在找方法&#xff0c;那么以下内容可以了解下。本文整理了三种简…

2c 操作符详解

1. 操作符分类&#xff1a; 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 2. 算术操作符 - * / % 1除了 % 操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。对于 / 操作…

NVIDIA NVLink-C2C

NVIDIA NVLink-C2C 文章目录 前言一、介绍1. 用于定制芯片集成的超快芯片互连技术2. 构建半定制芯片设计3. 使用 NVLink-C2C 技术的产品 二、NVLink-C2C 技术优势1. 高带宽2. 低延迟3. 低功率和高密度4. 行业标准协议 前言 将 NVLink 扩展至芯片级集成 一、介绍 1. 用于定制芯…

Candance仿真二阶米勒补偿OTA

1.OTA电路搭建目标——25Mhz GBW&#xff0c;65dB的增益 2.电路参照 3.candance电路搭建 实现步骤&#xff1a;应该是从下面这个公式开始推导 然后那个CL就是两边的那个CCa或CCb的大小 算出来就是gm75us

MongoDB-aggregate流式计算:带条件的关联查询使用案例分析

在数据库的查询中&#xff0c;是一定会遇到表关联查询的。当两张大表关联时&#xff0c;时常会遇到性能和资源问题。这篇文章就是用一个例子来分享MongoDB带条件的关联查询发挥的作用。 假设工作环境中有两张MongoDB集合&#xff1a;SC_DATA&#xff08;学生基本信息集合&…

基于微信小程序的旅游拼团系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Colorize: 0 variables Colorize is not activated for this file. VsCode

问题情况 解决步骤 1.找到setting.json文件 2.输入以下代码&#xff0c;保存setting.json文件 "colorize.languages": ["css", "javascript", "sass", "less", "postcss", "stylus", "xml"…

基于SpringBoot+Vue+MySQL的中医院问诊系统

系统展示 用户前台界面 管理员后台界面 医生后台界面 系统背景 随着信息技术的迅猛发展和医疗服务需求的不断增加&#xff0c;传统的中医院问诊流程已经无法满足患者和医院的需求。纸质病历不仅占用大量存储空间&#xff0c;而且容易丢失和损坏&#xff0c;同时难以实现信息的快…

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习04(环境准备)

4 创建docker容器 4.1创建网络 [rootlocalhost wutool]# docker network create -d macvlan --subnet192.168.137.0/24 --gateway192.168.137.2 --ip-range192.168.137.0/24 -o parentens33 nat 52af11381bfd655d175e4168265b2a507793e8fe48f119db846949ffd4dd27de [rootlocal…

【每天学个新注解】Day 15 Lombok注解简解(十四)—@UtilityClass、@Helper

UtilityClass 生成工具类的注解 将一个类通过注解变成一个工具类&#xff0c;并没有什么用&#xff0c;本来代码中的工具类数量就极为有限&#xff0c;并不能达到减少重复代码的目的 1、如何使用 加在需要委托将其变为工具类的普通类上。 2、代码示例 例&#xff1a; Uti…

设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)

文章目录 设计模式概述1、原型模式2、原型模式的使用场景3、优点4、缺点5、主要角色6、代码示例7、总结题外话关于使用序列化实现深拷贝 设计模式概述 创建型模式&#xff1a;工厂方法、抽象方法、建造者、原型、单例。 结构型模式有&#xff1a;适配器、桥接、组合、装饰器、…

构建高效新闻推荐系统:Spring Boot的力量

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

MacBook远程连接服务器,显示tensorboard的loss值

尼卡形态 GEAR-5 参考链接 当使用服务器进行模型训练时&#xff0c;想要使用MacBook查看一些可视化结果&#xff0c;如果远程服务器和本机在一个局域网内&#xff0c;可以通过以下命令解决&#xff1a; 登录服务器&#xff1a; 先用ssh工具重定向&#xff1a;ssh -L 16006:127…

java:pdfbox 删除扫描版PDF中文本水印

官网下载 https://pdfbox.apache.org/download.html下载 pdfbox-app-3.0.3.jar cd D:\pdfbox 运行 java -jar pdfbox-app-3.0.3.jar java -jar pdfbox-app-3.0.3.jar Usage: pdfbox [COMMAND] [OPTIONS] Commands:debug Analyzes and inspects the internal structu…

RTSP协议讲解

1.RTSP协议 rtsp&#xff0c;英文全称 Real Time Streaming Protocol&#xff0c;RFC2326&#xff0c;实时流传输协议&#xff0c;是 TCP/IP 协议体系中的一个应用层协议。 RTSP 交互流程 1&#xff09;OPTIONS C--->S 客户端向服务器端发现 OPTIONS&#xff0c;请求可用…

JVM(Java Virtual Machine) 详解

1. JVM 内存区域划分 一个 Java 写的程序&#xff0c;跑起来就得到了一个 Java 进程&#xff08;资源分配的基本单位&#xff09; JVM 上面运行的字节码指令 1) 程序计数器&#xff08;比较小的空间&#xff09;&#xff0c;保存了下一条要执行的指令的地址 这个不是 CPU 的…

API接口开发系列文章:构建高效、安全与可扩展的API服务

前言 在当今的数字化时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同系统、服务和应用的核心桥梁。无论是企业内部的数据交互&#xff0c;还是面向第三方的服务开放&#xff0c;API都扮演着至关重要的角色。本系列文章将深入探讨API接口开发的各个…