第六届字节跳动青训营第三课 | 豆包MarsCode AI 刷题

35 阅读6分钟

最大乘积区间问题

问题描述

小R手上有一个长度为 n 的数组 (n > 0),数组中的元素分别来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。

你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置 x 和结束位置 y (x ≤ y)。如果存在多个区间乘积相同的情况,优先选择 x 更小的区间;如果 x 相同,选择 y 更小的区间。

注意:数组的起始位置为 1,结束位置为 n


测试样例

样例1:

输入:n = 5, arr = [1, 2, 4, 0, 8]
输出:[1, 3]

样例2:

输入:n = 7, arr = [1, 2, 4, 8, 0, 256, 0]
输出:[6, 6]

样例3:

输入:n = 8, arr = [1, 2, 4, 8, 0, 256, 512, 0]
输出:[6, 7]

:::success 遍历,维护

:::

def solution(n: int, arr: list[int]) -> list[int]:
    # Edit your code here
    maxres = -1
    count = 1
    s, e = -1, -1
    si, ei = 1, 1

    for i in range(len(arr)):
        count *= arr[i]
        if count > maxres:
            s = si
            e = i + 1
            maxres = count
        if count == 0:
            count = 1
            si = i + 2
    # print([s, e])
    return [s, e]


if __name__ == "__main__":
    # Add your test cases here
    print(solution(5, [1, 2, 4, 0, 8]) == [1, 3])
    print(solution(7, [1, 2, 4, 8, 0, 256, 0]) == [6, 6])

小M的多任务下载器挑战

问题描述

小M的程序设计大作业是编写一个多任务下载器。在实现过程中,他遇到了一个问题:在一次下载过程中,总共有N个任务,每个任务会在第x秒开始,并持续y秒。小M需要知道,在同一时刻,最多有多少个任务正在同时下载,也就是计算出任务的最高并发数。

  • n 表示任务的数量。
  • array 是一个二维列表,每个元素为[x, y],表示任务的开始时间和持续时间,其中:
  • x 表示任务的开始时间;
  • y 表示任务的持续时间。

测试样例

样例1:

输入:n = 2 ,array = [[1, 2], [2, 3]]
输出:2

样例2:

输入:n = 4 ,array = [[1, 2], [2, 3], [3, 5], [4, 3]]
输出:3

样例3:

输入:n = 5 ,array = [[1, 3], [3, 4], [2, 2], [6, 5], [5, 3]]
输出:3

:::success map

:::

def solution(n, array):
    # Edit your code here
    m = {}
    for a in array:
        for i in range(a[0], a[0]+a[1]):
            if m.get(i):
                m[i] += 1
            else:
                m[i] = 1
    maxp = 0
    for v in m.values():
        if v > maxp:
            maxp = v

    return maxp


if __name__ == "__main__":
    # Add your test cases here
    print(
        solution(2, [[1,2], [2,3]]) == 2
    )
    print(
        solution(4, [[1,2], [2,3],[3,5], [4,3]]) == 3
    )

高质量编程简介及编码规范

  • 如何编写更简介清晰的代码
  • 常用Go语言程序优化工具
  • 熟悉GO程序性能分析工具
  • 了解工程中性能优化的原则和流程

高质量编程

  • 高质量编码简介
  • 编码规范
  • 性能优化建议

性能调优实战

  • 性能调优简介
  • 性能分析工具pprof实战
  • 性能调优案例

1.1 简介

编程原则

  • 实际应用场景千变万化,各种语言的特性和语法各不相同但是高质量编程遵循的原则是相通的
简单性
  • 消除“多余的复杂性”,以简单清晰的逻辑编写代码
  • 不理解的代码无法修复改进
可读性
  • 代码是写给人看的,而不是机器
  • 编写可维护代码的第一步是确保代码可读
生产力
  • 团队整体工作效率非常重要

-Go语言开发者 Dave Cheney

编码规范-注释

  • 注释应该解释代码作用
  • 注释因该结束时代码如何做的
  • 注释应该解释代码实现的原因
  • 代码应该解释代码什么情况会出错

编码规范-命名规范

变量

  • 简介胜于冗长
  • 缩略词全大写,但当其位于变量开头且不需要导出是,使用全小写
    • 例如使用ServeHTTP 而不是 ServeHttp
    • 使用 XMLHTTPRequest 或者 xmlHTTPRequest
  • 变量距离其被使用的地方越远,则需要写到越多的上下文信息
    • 全局变量在其名字中需要更多的上下文信息,使其在不同地方可以轻易辨认出其含义

函数

  • 函数不携带包名的上下文信息,因为包名和函数名总是成对出现的
  • 函数名尽量简短
  • 当名为foo的包某个函数返回类型 Foo 时,可以省略类型信息而不导致歧义
  • 当名为 foo 的包某个函数返回类型 T 时(T并不是 Foo),可以在函数名中加入类型信息

package

  • 只由小写字母组成。不包含大写字母和下划线等字符
  • 简短并包含一定的上下文信息。例如 schema、task 等
  • 不要与标准库同名。例如不要使用 sync 或者 strings

以下规则尽量满足,以标准库包名为例

  • 不使用常用变量名作为包名。例如使用 bufio 而不是 buf
  • 使用单数而不是复数。例如使用 encoding 而不是 encodings
  • 谨慎地使用缩写。例如使用 fmt 在不破坏上下文的情况下比 format 更加简短

编码规范-控制流程

  • 避免嵌套,保持正常流程清晰
    • 如果两个分支都包含return语句,则可以去除冗余的else
  • 尽量保持正常代码路径为最小缩进
    • 优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套

编码规范-错误和异常处理

简单错误

  • 简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误
  • 优先使用 errors.New 来创建匿名变量来直接表示
  • 简单错误如果有格式化的需求,使用 fmt.Errorf

panic

  • 不建议在业务代码中使用panic
  • 调用函数不包含recover 会造成程序崩溃
  • 若问题可以背屏蔽或解决,建议使用 error 代替 panic
  • 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic

recover

  • recover 只能在被defer 的函数中使用
  • 嵌套无法生效
  • 只在当前goroutine 生效
  • defer 的语句是后进先出

性能优化建议-Benchmark

slice

  • slice 预分配内存

Map

  • map 预分配内存

性能优化建议-字符串处理

package stringtest

import (
    "bytes"
    "strings"
)

func Plus(n int, str string) string {
    s := ""
    for i := 0; i < n; i++ {
        s += str
    }
    return s
}

func StrBuilder(n int, str string) string {
    var builder strings.Builder
    for i := 0; i < n; i++ {
        builder.WriteString(str)
    }
    return builder.String()
}
func ByteBuffer(n int, str string) string {
    buf := new(bytes.Buffer)
    for i := 0; i < n; i++ {
        buf.WriteString(str)
    }
    //fmt.Println(buf.String())
    return buf.String()
}

package stringtest

import "testing"

func BenchmarkPlus(b *testing.B) {
	for n := 0; n < b.N; n++ {
		Plus(1000, "hello")
	}

}
func BenchmarkStrBuilder(b *testing.B) {
	for n := 0; n < b.N; n++ {
		StrBuilder(1000, "hello")
	}
}
func BenchmarkByteBuffer(b *testing.B) {
	ByteBuffer(1000, "hello")
}

性能调优原则

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/block"