(C卷,200分)- 贪吃的猴子(Java & JS & Python & C)

在线OJ刷题

题目描述

一只贪吃的猴子,来到一个果园,发现许多串香蕉排成一行,每串香蕉上有若干根香蕉。每串香蕉的根数由数组numbers给出。

猴子获取香蕉,每次都只能从行的开头或者末尾获取,并且只能获取N次,求猴子最多能获取多少根香蕉。

输入描述

第一行为数组numbers的长度

第二行为数组numbers的值每个数字通过空格分开

第三行输入为N,表示获取的次数

输出描述

按照题目要求能获取的最大数值

备注

  • 1 ≤ numbers.length ≤ 100000
  • 1 ≤ numbers ≤ 100
  • 1 ≤ N ≤ numbers.length

用例

输入 7
1 2 2 7 3 6 1
3
输出 10
说明 第一次获取香蕉,无论是从行的开头或者末尾获取,得到的香蕉根数目为1, 但是,从行末尾获取能获取到最优的策略,后面可以直接得到香蕉根数目6和3。因此最终根数为1+6+3=10
输入 3
1 2 3
3
输出 6
说明 全部获取所有的香蕉,因此最终根数为1+2+3=6
输入 4
4 2 2 3
2
输出 7
说明 第一次获取香蕉为行的开头,第二次获取为行的末尾,因此最终根数为4+3=7

题目解析

本题我第一个思路是通过分支递归+缓存优化求解

但是经过测试,1 ≤ numbers.length ≤ 100000 数量级下,递归操作会StackOverflow,缓存cache数组占用的内存会超出限制。

后面思考了一下,无论我们怎么选,左边选择的,以及右边选择的,必然都是连续的,且是从头尾开始的连续,即不可出现下面情况:

因此,本题其实可以简化为,将n次分解为左边选择的个数,以及右边选择的个数。

以用例1画图示:

初始时,假设左边选择了0个,右边选择了n=3个,(黄色部分代表选择):

之后,左边选择1个,右边选择2个

之后,左边选择2,右边选择1个

最后,左边选择3个,右边选择0个

上面图示逻辑,我们除了需要计算初始时的leftSum和rightSum外,之后的状态均可以基于前一个状态求解,如下图所示

更多细节请看下面代码和注释。

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 len = parseInt(await readline());
  const nums = (await readline()).split(" ").map(Number);
  const n = parseInt(await readline());

  console.log(getResult(len, nums, n));
})();

function getResult(len, nums, n) {
  // 初始时,左边选择0个,因此左边选择的香蕉数为 0
  let leftSum = 0;

  // 初始时,右边选择n个,因此右边选择的香蕉数为 nums[len-n] ~ nums[len - 1] 这个n个元素之和
  let rightSum = 0;
  for (let i = len - n; i < len; i++) {
    rightSum += nums[i];
  }

  // 如果选择数n == len,即全选,此时直接返回初始rightSum
  if (len == n) {
    return rightSum;
  }

  // 如果不是全选
  // sum记录当前选择结果
  let sum = leftSum + rightSum;
  // ans记录所有选择结果中最大的
  let ans = sum;

  // l指向左边将要获得的,即左边获得一个
  let l = 0;
  // r指向右边将要失去的,即右边失去一个
  let r = len - n;

  while (l < n) {
    sum += nums[l++] - nums[r++];
    ans = Math.max(ans, sum);
  }

  return ans;
}

Java算法源码

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

public class Main {

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int len = Integer.parseInt(sc.nextLine());
    int[] nums = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
    int n = Integer.parseInt(sc.nextLine());

    System.out.println(getResult(len, nums, n));
  }

  public static int getResult(int len, int[] nums, int n) {
    // 初始时,左边选择0个,因此左边选择的香蕉数为 0
    int leftSum = 0;

    // 初始时,右边选择n个,因此右边选择的香蕉数为 nums[len-n] ~ nums[len - 1] 这个n个元素之和
    int rightSum = 0;
    for (int i = len - n; i < len; i++) {
      rightSum += nums[i];
    }

    // 如果选择数n == len,即全选,此时直接返回初始rightSum
    if (len == n) {
      return rightSum;
    }

    // 如果不是全选
    // sum记录当前选择结果
    int sum = leftSum + rightSum;
    // ans记录所有选择结果中最大的
    int ans = sum;

    // l指向左边将要获得的,即左边获得一个
    int l = 0;
    // r指向右边将要失去的,即右边失去一个
    int r = len - n;

    while (l < n) {
      sum += nums[l++] - nums[r++];
      ans = Math.max(ans, sum);
    }

    return ans;
  }
}

Python算法源码

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


# 算法入口
def getResult():
    # 初始时,左边选择0个,因此左边选择的香蕉数为 0
    leftSum = 0
    # 初始时,右边选择n个,因此右边选择的香蕉数为 nums[len-n] ~ nums[len - 1] 这个n个元素之和
    rightSum = sum(nums[length - n:])

    # 如果选择数n == len,即全选,此时直接返回初始rightSum
    if length == n:
        return rightSum

    # 如果不是全选
    # sum记录当前选择结果
    sumV = leftSum + rightSum
    # ans记录所有选择结果中最大的
    ans = sumV

    # l指向左边将要获得的,即左边获得一个
    l = 0
    # r指向右边将要失去的,即右边失去一个
    r = length - n

    while l < n:
        sumV += nums[l] - nums[r]
        ans = max(ans, sumV)
        l += 1
        r += 1

    return ans


# 算法调用
print(getResult())

C算法源码

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))

int getResult(int nums_len, const int nums[], int n) {
    // 初始时,左边选择0个,因此左边选择的香蕉数为 0
    int leftSum = 0;

    // 初始时,右边选择n个,因此右边选择的香蕉数为 nums[len-n] ~ nums[len - 1] 这个n个元素之和
    int rightSum = 0;
    for (int i = nums_len - n; i < nums_len; i++) {
        rightSum += nums[i];
    }

    // 如果选择数n == len,即全选,此时直接返回初始rightSum
    if (nums_len == n) {
        return rightSum;
    }

    // 如果不是全选
    // sum记录当前选择结果
    int sum = leftSum + rightSum;
    // ans记录所有选择结果中最大的
    int ans = sum;

    // l指向左边将要获得的,即左边获得一个
    int l = 0;
    // r指向右边将要失去的,即右边失去一个
    int r = nums_len - n;

    while (l < n) {
        sum += nums[l++] - nums[r++];
        ans = MAX(ans, sum);
    }

    return ans;
}

int main() {
    int nums_len;
    scanf("%d", &nums_len);

    int nums[nums_len];
    for (int i = 0; i < nums_len; i++) {
        scanf("%d", &nums[i]);
    }

    int n;
    scanf("%d", &n);

    printf("%dn", getResult(nums_len, nums, n));

    return 0;
}

免责声明:

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

0

评论0

站点公告

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