(B卷,200分)- 荒岛求生(Java & JS & Python & C)

题目描述

一个荒岛上有若干人,岛上只有一条路通往岛屿两端的港口,大家需要逃往两端的港口才可逃生。

假定每个人移动的速度一样,且只可选择向左或向右逃生。

若两个人相遇,则进行决斗,战斗力强的能够活下来,并损失掉与对方相同的战斗力;若战斗力相同,则两人同归于尽。

输入描述

给定一行非 0 整数数组,元素个数不超过30000;

正负表示逃生方向(正表示向右逃生,负表示向左逃生),绝对值表示战斗力,越左边的数字表示里左边港口越近,逃生方向相同的人永远不会发生决斗。

输出描述

能够逃生的人总数,没有人逃生输出0,输入异常时输出-1。

用例

输入 5 10 8 -8 -5
输出 2
说明 第3个人和第4个人同归于尽,第2个人杀死第5个人并剩余5战斗力,第1个人没有遇到敌人。

题目解析

本题可以利用栈结构解题。

解题思路如下:

我们可以假设所有数字都向左逃生,那么从左边出来的只有两种情况:

  • 正数
  • 负数

如果左边出来的是正数,则由于正数不能从左边逃生,而只能从右边出口逃生,因此我们不能算该正数逃生成功,并且该正数还会成为左边出来的负数的逃生阻力,因此我们将左边出来的正数缓存进栈中。

如果左边出来的是负数,则由于负数可以从左边出口逃生,因此此时,我们需要检查栈中有没有缓存的正数(阻力),如果有,则需要将左边逃出来的负数 和 栈顶的正数,进行pk(二者求和):

假设负数逃生成功个数为negative,正数逃生成功个数为positive

  • 若 pk > 0,则负数逃生失败,栈顶正数减少战斗力后重新入栈
  • 若 pk < 0,则负数打败了栈顶正数,负数减少战斗力,然后继续和新的栈顶正数pk:
  1. 若栈已经空了,则此负数逃生成功,我们将负数逃生成功个数negative+1
  2. 若栈未空,则继续pk逻辑
  • 若 pk == 0,则负数和栈顶正数同归于尽

按此逻辑,最后栈的大小其实就是逃生成功的正数个数postive,我们只要求和negative+postive即为题解。

JS算法源码

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

void (async function () {
  const nums = (await readline()).split(" ").map(Number);

  // 负数逃生的总人数
  let negative = 0;
  // 正数缓冲栈,注意该栈只缓存正数
  const positive = [];

  // 正序遍历nums,遍历出来的num,相当于从左边逃生
  for (let num of nums) {
    // 输入异常时输出-1
    if (num == 0) return console.log(-1);

    if (num > 0) {
      // 如果左边逃出来的是正数,则缓冲到栈中
      positive.push(num);
    } else {
      // 如果左边逃出来的是负数
      while (true) {
        if (positive.length == 0) {
          // 如果栈为空,即没有正数,此时左边逃出来的负数直接逃生成功
          negative++;
          break;
        }

        // 如果栈不为空,则栈中有缓冲的正数,此时负数需要和栈顶正数进行pk
        const pk = num + positive.pop();

        if (pk > 0) {
          // 如果pk结果大于0,则负数逃生失败,栈顶的正数减少战斗力
          positive.push(pk);
          break;
        } else if (pk < 0) {
          // 如果pk结果小于0,则负数pk成功,此时需要继续和新栈顶正数pk,即进入下一轮
          num = pk;
        } else {
          // 如果pk结果为0,则同归于尽
          break;
        }
      }
    }
  }

  // 最终逃生成功的人数:negative即负数逃生成功个数,positive.size()即正数逃生成功个数
  console.log(negative + positive.length);
})();

Java算法源码

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int[] nums = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
    System.out.println(getResult(nums));
  }

  public static int getResult(int[] nums) {
    // 负数逃生的总人数
    int negative = 0;

    // 正数缓冲栈,注意该栈只缓存正数
    LinkedList<Integer> positive = new LinkedList<>();

    // 正序遍历nums,遍历出来的num,相当于从左边逃生
    for (int num : nums) {
      // 输入异常时输出-1
      if (num == 0) return -1;

      if (num > 0) {
        // 如果左边逃出来的是正数,则缓冲到栈中
        positive.addLast(num);
      } else {
        // 如果左边逃出来的是负数
        while (true) {
          if (positive.size() == 0) {
            // 如果栈为空,即没有正数,此时左边逃出来的负数直接逃生成功
            negative++;
            break;
          }

          // 如果栈不为空,则栈中有缓冲的正数,此时负数需要和栈顶正数进行pk
          int pk = num + positive.removeLast();

          if (pk > 0) {
            // 如果pk结果大于0,则负数逃生失败,栈顶的正数减少战斗力
            positive.addLast(pk);
            break;
          } else if (pk < 0) {
            // 如果pk结果小于0,则负数pk成功,此时需要继续和新栈顶正数pk,即进入下一轮
            num = pk;
          } else {
            // 如果pk结果为0,则同归于尽
            break;
          }
        }
      }
    }

    // 最终逃生成功的人数:negative即负数逃生成功个数,positive.size()即正数逃生成功个数
    return negative + positive.size();
  }
}

Python算法源码

# 输入获取
nums = list(map(int, input().split()))


# 算法入口
def getResult():
    # 负数逃生的总人数
    negative = 0
    # 正数缓冲栈,注意该栈只缓存正数
    positive = []

    # 正序遍历nums,遍历出来的num,相当于从左边逃生
    for num in nums:
        # 输入异常时输出-1
        if num == 0:
            return -1

        if num > 0:
            # 如果左边逃出来的是正数,则缓冲到栈中
            positive.append(num)
        else:
            # 如果左边逃出来的是负数
            while True:
                if len(positive) == 0:
                    # 如果栈为空,即没有正数,此时左边逃出来的负数直接逃生成功
                    negative += 1
                    break

                # 如果栈不为空,则栈中有缓冲的正数,此时负数需要和栈顶正数进行pk
                pk = num + positive.pop()

                if pk > 0:
                    # 如果pk结果大于0,则负数逃生失败,栈顶的正数减少战斗力
                    positive.append(pk)
                    break
                elif pk < 0:
                    # 如果pk结果小于0,则负数pk成功,此时需要继续和新栈顶正数pk,即进入下一轮
                    num = pk
                else:
                    # 如果pk结果为0,则同归于尽
                    break

    # 最终逃生成功的人数:negative即负数逃生成功个数,positive.size()即正数逃生成功个数
    return negative + len(positive)


# 算法调用
print(getResult())

C算法源码

#include <stdio.h>

#define MAX_SIZE 30001

int getResult(int* nums, int nums_size);

/*
 * 栈结构定义(基于线性表)
 * 容器 stack 数组,容量上限MAX_SIZE
 * 栈中元素个数 stack_size
 * 压栈操作 stack_push
 * 弹栈操作 stack_pop
 */
int stack[MAX_SIZE];
int stack_size = 0;

void stack_push(int ele)
{
    if(stack_size < MAX_SIZE) {
        stack[stack_size++] = ele;
    }
}

int stack_pop()
{
    if(stack_size > 0) {
        return stack[--stack_size];
    }
}

// 程序入口
int main()
{
    int nums[MAX_SIZE];
    int nums_size = 0;
    while(scanf("%d", &nums[nums_size++])) {
        if(getchar() != ' ') break;
    }

    printf("%dn", getResult(nums, nums_size));

    return 0;
}

// 核心代码
int getResult(int* nums, int nums_size)
{
    // 负数逃生的总人数
    int negative = 0;

    // 正序遍历nums,遍历出来的num,相当于从左边逃生
    for(int i=0; i<nums_size; i++) {
        int num = nums[i];

        // 输入异常时输出-1
        if(num == 0) return -1;

        if(num > 0) {
            // 如果左边逃出来的是正数,则缓冲到栈中
            stack_push(num);
        } else {
            while(1) {
                // 如果左边逃出来的是负数
                if(stack_size == 0) {
                    // 如果栈为空,即没有正数,此时左边逃出来的负数直接逃生成功
                    negative++;
                    break;
                }

                // 如果栈不为空,则栈中有缓冲的正数,此时负数需要和栈顶正数进行pk
                int pk = num + stack_pop();

                if(pk > 0) {
                    // 如果pk结果大于0,则负数逃生失败,栈顶的正数减少战斗力
                    stack_push(pk);
                    break;
                } else if(pk < 0) {
                    // 如果pk结果小于0,则负数pk成功,此时需要继续和新栈顶正数pk,即进入下一轮
                    num = pk;
                } else {
                    // 如果pk结果为0,则同归于尽
                    break;
                }
            }
        }
    }

    // 最终逃生成功的人数:negative即负数逃生成功个数,stack_size即正数逃生成功个数
    return negative + stack_size;
}

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?