Golang解决方案为何失败而Python却能通过?

Golang解决方案为何失败而Python却能通过? 我正在通过完成简单的编程挑战来自学Go语言。我在Python中解决的一个问题是这个:

https://codeforces.com/contest/463/problem/B

我通过所有测试的Python代码如下:

import math
import os

file = os.sys.stdin

n = int(file.readline().split(' ')[0])

heights = file.readline().split(' ')
heights.insert(0, 0)

cost = 0
energy = 0

for i, _ in enumerate(heights):
    if i == 0:
        continue
    gain = int(heights[i - 1]) - int(heights[i])
    energy += gain

    if energy < 0:
        cost += -energy
        energy = 0

print(cost)

然而,当我将其翻译成Go语言时,我的解决方案失败了。我的Go语言解决方案:

package main

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


func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	n, err := strconv.Atoi(scanner.Text())
	check(err)

	scanner.Scan()
	heights := strings.Fields(scanner.Text())
	heights = append([]string{"0"}, heights...)

	cost := 0
	energy := 0

	for i := 1; i <= n; i ++ {
		a, err := strconv.Atoi((heights[i - 1]))
		check(err)

		b, err := strconv.Atoi((heights[i]))
		check(err)

		gain := a - b
		energy += gain

		if energy < 0 {
			cost += -energy
			energy = 0
		}
	}

	fmt.Println(cost)
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}

原因是它在测试9上失败了。以下是错误信息:

Screenshot 2021-06-14 at 16.04.36

现在看起来字符串转换出了点问题。我已经阅读了文档,但无法弄清楚是怎么回事。有人能指导我一下这可能是什么问题吗?

除了strings.Split(),我还使用了strings.Fields()函数,但也失败了。

谢谢!


更多关于Golang解决方案为何失败而Python却能通过?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你的程序需要一个来自标准输入(例如命令行)的参数。如果没有提供任何有效值,第16行将会报错。

https://play.golang.org/p/9-V6AnYx_R9

更多关于Golang解决方案为何失败而Python却能通过?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢 @geosoft1

我现在可以看到问题出在第16行。但我仍然不确定具体发生了什么,因为Codeforces服务器应该提供输入,正如错误消息附带的图片所示。

对于失败的测试用例,第一行应该是100000,第二行是一串数字。

有没有什么原因导致Codeforces服务器在运行程序时没有读取到100000这个输入?我是不是在什么地方犯了错误?

编辑:我找到原因了——我使用的是Mac系统,换行符是‘\n’,而服务器使用的是回车换行‘\r\n’作为换行符。切换到Windows风格的换行符后问题就解决了。

你的Go代码失败是因为输入处理逻辑有问题。问题出在读取n的方式上。

在Python代码中,你只读取了第一个数字:

n = int(file.readline().split(' ')[0])

但在Go代码中,你读取了整个第一行并尝试转换为整数:

scanner.Scan()
n, err := strconv.Atoi(scanner.Text())  // 如果第一行有多个数字,这会失败

实际上,Codeforces的输入格式是第一行只有一个整数n,但你的代码假设第一行可能有多个数字。然而问题463B的输入格式确实是第一行只有一个整数n,所以这里应该没问题。

真正的问题在于你的循环条件。在Python中,你遍历的是heights列表:

for i, _ in enumerate(heights):
    if i == 0:
        continue
    # 处理逻辑

但在Go中,你只遍历到n

for i := 1; i <= n; i ++ {
    // 处理逻辑
}

这会导致如果heights的长度不等于n,你的循环就会出错。实际上,输入的第二行可能有n个高度值,但你的heights切片在开头插入了一个"0",所以长度变成了n+1

正确的Go解决方案应该是:

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	n, _ := strconv.Atoi(scanner.Text())

	scanner.Scan()
	heightsStr := strings.Fields(scanner.Text())
	
	// 直接在切片前添加0,而不是创建新切片
	heights := make([]int, n+1)
	heights[0] = 0
	for i := 1; i <= n; i++ {
		h, _ := strconv.Atoi(heightsStr[i-1])
		heights[i] = h
	}

	cost := 0
	energy := 0

	for i := 1; i <= n; i++ {
		gain := heights[i-1] - heights[i]
		energy += gain

		if energy < 0 {
			cost += -energy
			energy = 0
		}
	}

	fmt.Println(cost)
}

或者更简洁的版本:

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	n, _ := strconv.Atoi(scanner.Text())

	scanner.Scan()
	heightsStr := strings.Fields(scanner.Text())

	prev := 0
	cost := 0
	energy := 0

	for i := 0; i < n; i++ {
		h, _ := strconv.Atoi(heightsStr[i])
		gain := prev - h
		energy += gain

		if energy < 0 {
			cost += -energy
			energy = 0
		}
		prev = h
	}

	fmt.Println(cost)
}

关键区别:

  1. 使用整数切片而不是字符串切片,避免重复转换
  2. 正确处理循环边界,确保处理所有高度值
  3. 简化逻辑,不需要在切片前插入"0",可以直接从0开始计算

这样应该能通过所有测试用例。

回到顶部