题目描述与示例
题目描述
有一个荒岛,只有左右两个港口,只有一座桥连接这两个港口,现在有一群人需要从两个港口逃生,有的人往右逃生,有的往左逃生,如果两个人相遇,则 pk,体力值大的能够打赢体力值小的,体力值相同则同归于尽,赢的人才能继续往前逃生,并减少相应的体力
输入描述
系列非 0
整数,用空格隔开,正数代表向右逃生,负数代表向左逃生
输出描述
最终能够逃生的人数
示例一
输入
5 10 8 -8 -5
输出
5 5
说明
8` 与 `-8` 相遇,同归于尽,`10` 遇到`-5`,打赢并减少五点体力,最终逃生的为`[5,5]`,均从右侧港口逃生,输出 `2
示例二
输入
5 6 -10
输出
1
解题思路
注意,本题和LC735. 行星碰撞几乎完全一致。唯一的区别在于,本题出现体力不相等的情况,需要进行减法操作。
代码
Python
# 题目:2023B-荒岛求生
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:栈
# 代码看不懂的地方,请直接在群上提问
# 输入体力数组
nums = list(map(int, input().split()))
# 初始化一个栈,用于维护逃生过程中的人的体力
stack = list()
# 从左到右遍历逃生的人的体力
for num in nums:
# 当前逃生的人向右移动的情况
if num > 0:
# 无需考虑栈顶元素的方向或值,直接入栈即可
stack.append(num)
# 当前逃生的人向左移动的情况
else:
# 进行while循环,退出循环的条件为以下三个条件中的一个
# 1. 栈为空栈,即原栈中没有向左的人,经过pk后所有向右的人都倒下;
# 2. 栈顶元素向左,即原栈中包含若干向左的人,经过pk后所有向右的人都倒下;
# 3. num为0,即经过pk后该人倒下
while len(stack) != 0 and stack[-1] > 0 and num != 0:
# 当前向左的人和栈顶向右的人的体力相等,则两个人均倒下
if abs(num) == stack[-1]:
# 向右的人倒下,出栈
stack.pop()
# 当前向左的人倒下,修改num为0
num = 0
# 当前向左的人的体力大于栈顶向右的人
elif abs(num) > stack[-1]:
# 向右的人倒下,出栈
right = stack.pop()
# 当前向左的人损失right点体力
# 注意num是个负数,right是个正数,使用加法修改num
num += right
# 当前向左的人的体力小于栈顶向右的人
elif abs(num) < stack[-1]:
# 向右的人损失abs(num)点体力,但仍未倒下,无需出栈
# 此处使用stack[-1] += num也可以
stack[-1] += num
# 当前向左的人倒下,修改num为0
num = 0
# 如果经过pk后,num的体力仍不为0,则需要入栈
if num != 0:
stack.append(num)
print(" ".join(str(num) for num in stack))
Java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] numsArr = scanner.nextLine().split(" ");
int n = numsArr.length;
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(numsArr[i]);
}
List<Integer> stack = new ArrayList<>();
for (int num : nums) {
if (num > 0) {
stack.add(num);
} else {
int i = stack.size() - 1;
while (i >= 0 && stack.get(i) > 0 && num != 0) {
if (Math.abs(num) == stack.get(i)) {
stack.remove(i);
num = 0;
} else if (Math.abs(num) > stack.get(i)) {
int right = stack.remove(i);
num += right;
} else if (Math.abs(num) < stack.get(i)) {
stack.set(i, stack.get(i) + num);
num = 0;
}
i--;
}
if (num != 0) {
stack.add(num);
}
}
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < stack.size(); i++) {
result.append(stack.get(i));
if (i < stack.size() - 1) {
result.append(" ");
}
}
System.out.println(result.toString());
}
}
C++
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string line;
getline(cin, line);
stringstream ss(line);
vector<int> nums;
int num;
while (ss >> num) {
nums.push_back(num);
}
vector<int> stack;
for (int num : nums) {
if (num > 0) {
stack.push_back(num);
} else {
int i = stack.size() - 1;
while (i >= 0 && stack[i] > 0 && num != 0) {
if (abs(num) == stack[i]) {
stack.erase(stack.begin() + i);
num = 0;
} else if (abs(num) > stack[i]) {
int right = stack[i];
stack.erase(stack.begin() + i);
num += right;
} else if (abs(num) < stack[i]) {
stack[i] += num;
num = 0;
}
i--;
}
if (num != 0) {
stack.push_back(num);
}
}
}
for (int i = 0; i < stack.size(); i++) {
cout << stack[i];
if (i < stack.size() - 1) {
cout << " ";
}
}
cout << endl;
return 0;
}
时空复杂度
时间复杂度:O(N)
。仅需一次遍历数组。
空间复杂度:O(N)
。栈所占用的额外空间。
说明
华为OD机试有三道题⽬,第⼀道和第⼆道属于简单或中等题,分值为 100 分,第三道为中等或困难题,分值为 200分,总分为 400 分。
机试分数越⾼评级越⾼,⼯资也就越⾼。
关于华为 OD 机试更加详细的介绍可以查看这篇⽂章:华为OD机考须知
关于机考题目汇总可以看这篇文章:华为OD机试真题 2023 A+B+C+D卷 + 2024新卷(Python&Java&C++)⽬录汇总(每⽇更新)