文章目录
- 问题
- bufio.NewReader
- 高效的原理
- 再次提交
问题
最近在练习牛客上单调栈题目时,要求自己处理出入输出,也就是读题库要求的输入,计算最终结果,并打印输出
当我用fmt.Scan
处理输入,用fmt.Println
处理输出时:
package main
import "fmt"
func main() {
// 读取测试数据
var n int
fmt.Scan(&n)
nums := make([]int, n)
for i := 0; i < n; i++ {
fmt.Scan(&nums[i])
}
// 执行具体算法
res := f(nums)
// 输出答案
for _, v := range res {
fmt.Println(fmt.Sprintf("%d %d", v[0], v[1]))
}
}
在数据量较大时超时了。。。
算法本身已经是最优复杂度了,那问题只可能在输入输出上
于是研究了下用go写算法笔试题时,怎么高效处理输入输出
bufio.NewReader
读取输入:需要用带缓冲的bufio.NewReader
包装os.Stdin
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取第一行n
nStr, _ := reader.ReadString('\n')
n, _ := strconv.Atoi(nStr[:len(nStr)-1])
nums := make([]int, n)
// 读取第二行数据
numsStr, _ := reader.ReadString('\n')
numsStrArr := strings.Split(numsStr[:len(numsStr)-1], " ")
// 解析读取每个num
for i := 0; i < n; i++ {
curNum, _ := strconv.Atoi(numsStrArr[i])
nums[i] = curNum
}
}
这里用到reader.ReadString('\n')
方法读取每一行,表示一直读,直到遇到换行符为止
读取到每一行数据就好办了,按照空格分隔,转换成数字,调算法处理
注意:reader.ReadString返回结果的最后有换行符,需要手动去掉
注意:windows换行符时 \r\n,linux/mac的换行符是:\n
如果在自己的windows电脑写代码,但提交到OJ平台(一般在linux环境执行)时,需要注意两个平台的换行符是不同的
也可以用reader.ReadLine
,读取一行字符串,其返回结果没有换行符,也就不用关心环境是windows还是linux,对程序员友好
reader := bufio.NewReader(os.Stdin)
// 读第一行
nStr, _, _ := reader.ReadLine()
n, _ := strconv.Atoi(string(nStr))
nums := make([]int, n)
// 读第二行
numsStr, _, _ := reader.ReadLine()
// 下面处理数据
numsStrArr := strings.Split(string(numsStr), " ")
for i := 0; i < n; i++ {
curNum, _ := strconv.Atoi(numsStrArr[i])
nums[i] = curNum
}
输出答案也要用bufio.NewWriter包装os.Stdout
writer := bufio.NewWriter(os.Stdout)
for _, v := range res {
// 先将答案输出到缓冲区,注意每行末尾增加换行符
writer.WriteString(fmt.Sprintf("%d %d", v[0], v[1]) + "\n")
}
// 最后flush
writer.Flush()
高效的原理
bufio.Reader
:先把一把大数据读到缓冲区中(默认4kb),后面程序调ReadString时,就是从缓冲区读。只会在一开始发生一次系统调用,后面都是进程内的函数调用,非常快bufio.Writer
:先把数据写到缓冲区中(默认4kb),直到缓冲区满,或手动调Flush时才发起系统调用将数据写到os.Stdout
也就是说,通过缓冲区来降低系统调用的次数,通过空间换时间,速度当然变快了
再次提交
这次就通过了