[大厂真题-京东]牛牛与切割机

一、真题描述

有一个序列 a1,a2,...,ana1​,a2​,...,an​ , 牛牛将对这个序列切割一刀(划分分成两个不相交的非空序列,一个序列为 a1,…,apa1​,…,ap​,另一个序列为 ap+1,…,anap+1​,…,an​),牛牛切割的代价为两个序列元素和的乘积。牛牛想知道切割代价最小是多少。

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

示例1:

输入例子:5

                  1 2 3 4 5

输出例子:14

例子说明:序列被划分为1 和 2 3 4 5,右边和为 14。

示例2:

输入例子:4

                  2 1 3 4

输出例子:16

例子说明:序列被划分为 2 和 1 3 4。

 

二、解题思路&代码实现

1、解题思路:

(1) 前缀和优化计算

为了高效地求出每种切割方式下的两段和,我们可以使用 前缀和数组 prefixSum[]

定义:

prefixSum[i] = a[0] + a[1] + ... + a[i - 1]

这样对于任意的 p,可以快速得到:

  • sum1 = prefixSum[p + 1]
  • sum2 = prefixSum[n] - sum1

(2)遍历所有合法切割点

p = 0p = n - 2(即切割点在第一个元素之后、最后一个元素之前),依次计算每个切割点的代价,并记录最小值。

2、时间复杂度分析:

  • 构建前缀和数组:O(n)
  • 遍历所有切割点:O(n)
  • 总时间复杂度:O(n)

空间复杂度:O(n)(也可以优化到 O(1),只需维护当前总和即可)

3、代码实现:

java :

import java.util.Scanner;

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

        // 读取一行输入并转换为整数数组
        String[] numsStr = in.nextLine().split("\\s+");
        int[] a = new int[numsStr.length];
        for (int i = 0; i < numsStr.length; i++) {
            a[i] = Integer.parseInt(numsStr[i]);
        }

        System.out.println(minCutCost(a));
    }

    public static int minCutCost(int[] a) {
        int n = a.length;
        if (n <= 1) return 0;

        int[] prefixSum = new int[n + 1];
        for (int i = 0; i < n; i++) {
            prefixSum[i + 1] = prefixSum[i] + a[i];
        }

        int minCost = Integer.MAX_VALUE;
        for (int p = 0; p < n - 1; p++) {
            int sum1 = prefixSum[p + 1];
            int sum2 = prefixSum[n] - sum1;
            int cost = sum1 * sum2;
            if (cost < minCost) {
                minCost = cost;
            }
        }

        return minCost;
    }
}

 

示例输入输出

输入:

int[] a = {1, 2, 3, 4, 5};

所有可能的切割及其代价: 

切割点左边和右边和代价
p=011414
p=131236
p=26954
p=310550

输出:

14

php :

<?php

function minCutCost($a) {
    $n = count($a);
    if ($n <= 1) return 0;

    // 构建前缀和数组
    $prefixSum = array_fill(0, $n + 1, 0);
    for ($i = 0; $i < $n; $i++) {
        $prefixSum[$i + 1] = $prefixSum[$i] + $a[$i];
    }

    $minCost = PHP_INT_MAX;
    for ($p = 0; $p < $n - 1; $p++) {
        $sum1 = $prefixSum[$p + 1];
        $sum2 = $prefixSum[$n] - $sum1;
        $cost = $sum1 * $sum2;
        if ($cost < $minCost) {
            $minCost = $cost;
        }
    }

    return $minCost;
}

// 使用 fscanf 读取输入
$handle = fopen("php://stdin", "r");

// 假设第一行输入表示数组长度
$len = 0;
fscanf($handle, "%d", &$len);

// 然后读取 len 个整数
$a = [];
for ($i = 0; $i < $len; $i++) {
    $num = 0;
    fscanf($handle, "%d", &$num);
    $a[] = $num;
}

// 计算并输出结果
echo minCutCost($a) . PHP_EOL;

fclose($handle);

golang :

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func minCutCost(a []int) int {
	n := len(a)
	if n <= 1 {
		return 0
	}

	prefixSum := make([]int, n+1)
	for i := 0; i < n; i++ {
		prefixSum[i+1] = prefixSum[i] + a[i]
	}

	minCost := 1 << 63 // 初始化为最大值
	for p := 0; p < n-1; p++ {
		sum1 := prefixSum[p+1]
		sum2 := prefixSum[n] - sum1
		cost := sum1 * sum2
		if cost < minCost {
			minCost = cost
		}
	}

	return minCost
}
func main() {
	// 读取数组长度
	var n int
	fmt.Print("请输入数组长度 n: ")
	_, err := fmt.Scan(&n)
	if err != nil || n < 2 {
		fmt.Println("输入错误,n 必须大于等于 2")
		return
	}

	// 读取 n 个整数
	a := make([]int, n)
	fmt.Printf("请输入 %d 个整数(空格分隔):\n", n)
	for i := 0; i < n; i++ {
		_, err := fmt.Scan(&a[i])
		if err != nil {
			fmt.Println("输入错误:请输入整数")
			return
		}
	}

	// 计算并输出结果
	fmt.Println("最小切割代价为:", minCutCost(a))
}

//第二种输入输出实现
/*func main() {
	reader := bufio.NewReader(os.Stdin)
	line, _ := reader.ReadString('\n')
	numsStr := strings.Fields(line)
	nums := make([]int, len(numsStr))
	for i, s := range numsStr {
		nums[i], _ = strconv.Atoi(s)
	}
	fmt.Println(minCutCost(nums))
}*/
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值