关于golang:Golangfunction

函数 函数的各种格局1.1 无返回值函数1.2 无参函数1.3 无参、有返回值函数1.4 对函数的返回值变量进行申明1.5 对函数参数的类型进行简写1.6 有多个返回值的函数1.7 可变函数(相当于slice作参数,必须置于开端)代码: package mainimport "fmt"//无返回值函数func f1(x int, y int) { fmt.Println(x + y)}//无参函数func f2() { fmt.Println("我是个无参数函数")}//无参、但有返回值的函数func f3() int { return 17}//对函数的返回值变量进行申明func f4(x int, y int) (ret int) { ret = x + y return}//对函数参数的类型进行简写func f5(x, y int) { fmt.Println(x + y)}//有多个返回值的函数func f6() (ret string, ret2 bool) { ret = "世界战争" ret2 = false return}//可变函数func f7(x string, y ...int) { fmt.Println(x) fmt.Println(y)}func main() { x := 1 y := 2 f1(x, y) f2() f3() f4(x, y) f5(x, y) m, n := f6() fmt.Println(m, n) f7("打倒美帝", 1, 2, 3)}运行后果: ...

March 5, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法其他多数元素哈希表摩尔投票法

题目:给定一个大小为 n 的数组,找到其中的少数元素。少数元素是指在数组中呈现次数 大于 ⌊ n/2 ⌋ 的元素。 你能够假如数组是非空的,并且给定的数组总是存在少数元素。 链接: 力扣Leetcode—中级算法—其余—少数元素. 示例 1: 输出:[3,2,3]输入:3示例 2: 输出:[2,2,1,1,1,2,2]输入:2标签:数组、哈希表、分治、计数、排序 思路:简略的想法是应用哈希表或者排序实现,遍历一次数组,将每个数呈现的次数存入哈希表,当次数大于n/2时返回即可,代码如下: 全副Go代码如下: package mainimport ( "fmt")func majorityElement(nums []int) int { var res int m := make(map[int]int) n := len(nums) if n < 1 { return 0 } else if n == 1 { return nums[0] } else { for _, v := range nums { m[v]++ } for key, v := range m { if v > n/2 { res = key break } else { continue } } return res }}func main() { a := []int{8, 8, 7, 7, 7} fmt.Println(majorityElement(a))}提交截图:然而该计划空间复杂度为O(n),不符合要求O(1) ...

March 4, 2022 · 1 min · jiezi

关于golang:第三十三期golang校招面试经历分享-畅天游

1、go init 的执行程序,留神是不按导入规定的(这里是编译时按文件名的程序执行的)2、interface nil 比拟。3、原生map非线程平安,加锁以及sync.Map{}的实现。4、channel no buffer以及buffer的区别。5、如何删除slice两头的元素(s = append(s[:i],s[i+1,]...),我感觉其实就是切片的利用。6、怎么保留在程序解体时的数据,过后没了解到,我感觉是(defer+reciver)7、go实现一个SQL Pool(能够借鉴database/sql pool的实现)8、go 怎么管制查问timeout (context)9、docker image 的区别。10、mysql的主从备份。11、redis 的五种数据结构,以及其中一个用法。12、git 创立分支。13、less more 以及linux 中如何查看日志中某一行的数据 。(sed)14、查看过程 。(ps)

March 4, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法其他逆波兰表达式求值栈

题目:依据 逆波兰表示法,求表达式的值。 无效的算符包含 +、-、*、/ 。每个运算对象能够是整数,也能够是另一个逆波兰表达式。 留神 两个整数之间的除法只保留整数局部。 能够保障给定的逆波兰表达式总是无效的。换句话说,表达式总会得出无效数值且不存在除数为 0 的状况。 链接: 力扣Leetcode—中级算法—其余—逆波兰表达式求值. 示例 1: 输出:tokens = ["2","1","+","3","*"]输入:9解释:该算式转化为常见的中断算术表达式为:((2 + 1) * 3) = 9示例 2: 输出:tokens = ["4","13","5","/","+"]输入:6解释:该算式转化为常见的中断算术表达式为:(4 + (13 / 5)) = 6示例 3: 输出:tokens = ["10","6","9","3","+","-11","","/","","17","+","5","+"]输入:22解释:该算式转化为常见的中断算术表达式为: ((10 (6 / ((9 + 3) -11))) + 17) + 5= ((10 (6 / (12 -11))) + 17) + 5= ((10 * (6 / -132)) + 17) + 5= ((10 * 0) + 17) + 5= (0 + 17) + 5= 17 + 5= 22逆波兰表达式: ...

March 4, 2022 · 2 min · jiezi

关于golang:console打印动态进度条

type Reader struct { io.Reader Total int64 Written int64}func (r *Reader) Read(b []byte) (n int, err error) { n, err = r.Reader.Read(b) r.Written += int64(n) fmt.Printf("\r进度 %.2f%%", float64(r.Written*10000/r.Total)/100) return}留神 "\r",将是保障在管制台上同一个中央,数字不停变动的要害,同样的, 在java中也同样实用 for (int i = 1; i <= 100; i++) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print("\r我的进度是" + i + "%"); }

March 3, 2022 · 1 min · jiezi

关于golang:Go进阶并发编程WaitGroup

WaitGroup 是开发过程中常常应用的并发控制技术,用来在程序中管制期待一组 goroutine 完结。 实现原理数据结构WaitGroup 的数据结构包含了一个 noCopy 的辅助字段,一个 state1 记录 WaitGroup 状态的数组: noCopy 的辅助字段;state1,一个具备复合意义的字段,蕴含 WaitGroup 的计数、阻塞在检查点的 waiter 数和信号量。type WaitGroup struct { // 防止复制应用的一个技巧,能够通知 vet 工具违反了复制应用的规定 noCopy noCopy // 前 64bit(8bytes) 的值分成两段,高 32bit 是计数值,低 32bit 是 waiter 的计数 // 另外 32bit 是用作信号量的 // 因为 64bit 值的原子操作须要 64bit 对齐,然而 32bit 编译器不反对,所以数组中的元素在不同的架构中不一样,具体解决看上面的办法 // 总之,会找到对齐的那 64bit 作为 state,其余的 32bit 做信号量 state1 [3]uint32}// 失去state的地址和信号量的地址func (wg *WaitGroup) state() (statep *uint64, semap *uint32) { if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 { // 如果地址是 64bit 对齐的,数组前两个元素做 state,后一个元素做信号量 return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2] } else { // 如果地址是 32bit 对齐的,数组后两个元素用来做 state,它能够用来做 64bit 的原子操作,第一个元素 32bit 用来做信号量 return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0] }}在 64 位环境下,state1 的第一个元素是 waiter 数,第二个元素是 WaitGroup 的计数值,第三个元素是信号量。 ...

March 3, 2022 · 2 min · jiezi

关于golang:软件设计的沉静|ONES-技术人

蔡明金自称他是吉他「十年初学者」。在读大学期间,他跟搭档组过乐队。现在,投身技术工作,他对合作、编程和软件设计都有「沉静式」了解。 以下是蔡明金与 ONES 故事——局部来自其自述,局部来自他某次技术分享会的内容。 沉着解决问题我以前的脾气比拟火暴,如果发现产品设计上的不统一,就会怼回去,毫不留情面。 当初我有了很大的转变。我感觉,可能平心静气地与他人在一件事件上达成统一,朝着独特的指标去实现工作,也是很好的体验。 学会沉着地解决问题、解决人际关系,是我进入 ONES 工作两年多以来看失去的成长。尽管可能跟我的年纪渐长有关系,但更重要的是受到的 ONES 工作气氛陶冶。 在有些公司,部门之间边界清晰、若明若暗。而 ONES 是一家认真做产品的公司,部门之间的分割和单干很多,所以平时理解彼此的习惯和处境,急躁地沟通,这样下来从后果来看效率也并不会升高。 最近,我梳理了《软件设计的哲学》这本著述的内容,和共事们做了一次交换。 战略性编程哲学是一种沉着的解决形式。我之所以做这个分享,次要是想通知大家,哲学其实是工作过程中的点滴,指标是让大家更无意识性地编码。总的来讲,是**心愿大家要进行战略性编程,而不是战术性编程。**软件设计是工程、数学、艺术、文化的交融发明。软件设计外面有「门道」。 软件设计整体指标是缩小复杂度。而所谓的复杂度反映的是:软件系统的构造的了解、批改的难易水平。 如果你尝试了一个办法然而没有缩小复杂度,你很可能没必要保留它。 具体来看,简单的特色包含: 1.当新增个性时,须要批改大量的代码;2.当须要开发一个性能时,开发人员须要理解许多常识;3.当新增/批改性能时,不能显著地晓得要批改哪些代码。 能够概括为:零碎是不是难以了解,零碎是不是难以批改——如果是,那么这就是简单的。 复杂度并不是由繁多的微小谬误产生的,它是由很多小谬误累积而成的。一个简略的依赖和艰涩的名称定义,并不足以影响整个零碎。然而千里之行;始于足下,数量足够多时会导致复杂度。最初,任何小的改变都会影响整个零碎。 接口是一种他人须要记住的信息,那么过于多的接口,或者过于简单的接口都会减轻他人的认知及了解累赘。这就是一种复杂性的引入。 「异样」一词是指代任何会改变程序中失常管制流程的不常见条件。充分考虑容错的状况下,异样解决能够占零碎中所有代码的很大一部分,但错误处理并不是越多越好,这会导致一种过分进攻的格调,其中任何看起来甚至有点可疑的货色都会抛出异样,这就变成了异样的泛滥,从而减少了零碎的复杂性。 为了疾速实现一个工作,兴许你有一个截止期限,此时长期的效益并不是首要思考的事件。你没有花更多的工夫寻找好的设计,你只是想疾速解决问题,你想的是写一堆代码去实现性能,越快越好——这只是战术性编程,不可取。 战略性编程是从小事做起,是一直地在当下做“小投资”,一直地寻求更好的设计,以换取长期的复利回报。

March 3, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法其他两整数之和位运算

题目:给你两个整数 a 和 b ,不应用 运算符 + 和 - ,计算并返回两整数之和。 链接: 力扣Leetcode—中级算法—其余—两整数之和. 示例 1: 输出:a = 1, b = 2输入:3示例 2: 输出:a = 2, b = 3输入:5标签:位运算、数学 思路:题目要求了不能应用运算符 + 和 - ,于是,咱们应用位运算来解决这个问题。 位运算中的两数加法,也就上面这四种: 0 + 0 = 00 + 1 = 11 + 0 = 11 + 1 = 0 (进位)咱们来看一个例子: a = 5 = 0101b = 4 = 0100a ^ b 如下:(异或:如果a、b两个值不雷同,则异或后果为1。如果a、b两个值雷同,异或后果为0。) 0 1 0 10 1 0 0-------0 0 0 1a ^ b 失去了一个 无进位加法 后果,如果要失去 a + b 的最终值,咱们还要找到 进位 的数,把这二者相加。在位运算中,咱们能够应用 与 操作取得进位: ...

March 3, 2022 · 1 min · jiezi

关于golang:第三十二期春招-Golang实习面经-七牛

一面(问的问题太多,只记住这些)1.红黑树和二叉搜寻树的区别2.红黑树和均衡二叉树的区别,相比于均衡二叉树。3.解决哈希抵触的办法4.一致性哈希算法5.LRU算法LRU和LFU的区别?LRU强调的是什么?6.slice底层,append底层什么的。7.从切片中取切片,底层会变动吗,什么时候会变动?答复了扩容,面试官说还有,没答上来,最初也忘了问。8.经典快排思路 稳不稳固?9.归并排序思路 工夫复杂度?10.Go的调度 MPG11.缓存击穿和缓存穿过区别怎么解决这俩个问题12.Go个别怎么取map13.如果一个map没申请空间,去向外面取值,会产生什么状况。我记得如同是返回默认值,面试官问我确定吗…14.用户态线程和内核态线程区别15.虚拟内存?操作系统怎么实现虚拟内存?16.get和post的区别,post和put的区别17.tcp三次握手18.为什么握手是三次挥手是四次19.time wait20.finishedwait1和finshedwait221.listen 和 accept bloglog22.快重传,快复原23.用户态和内核态在内存散布上是什么样的24.有缓存的管道和没有缓存的管道的区别25.groutinue什么时候会被挂起26.defer defer执行效率27.判断链表有没有环,入环节点 只记得这么多 二面我的项目 巴拉巴拉啦啦啦。。。面试官始终在给我扩大 。。。。。说了一大堆 TCP怎么实现牢靠传输从超时重传讲到流量管制到拥塞管制以及四个具体措施数据库的四个隔离级别Go的调度,长处sync.Map 底成原理内存的散布手撕,判断有没有入环节点反诘

March 3, 2022 · 1 min · jiezi

关于golang:go变量

package mainimport ( "fmt" "reflect" "unsafe")func main() { var s1, s2 string var sh1, sh2 *reflect.StringHeader s1 = "abcd" s2 = s1 sh1 = (*reflect.StringHeader)(unsafe.Pointer(&s1)) fmt.Println(sh1.Data, sh1.Len, &s1) sh2 = (*reflect.StringHeader)(unsafe.Pointer(&s2)) fmt.Println(sh2.Data, sh2.Len, &s2) s2 = "cdef123" sh2 = (*reflect.StringHeader)(unsafe.Pointer(&s2)) fmt.Println(sh2.Data, sh2.Len, &s2)}

March 2, 2022 · 1 min · jiezi

关于golang:Go-语言社区新提案-arena可优化内存分配

近日,Go 语言社区正在探讨名为「arena」的新提案。 据介绍,arena 是一种从间断的内存区域调配一组内存对象的办法,其长处是从 arena 调配对象通常比个别内存调配更无效,更重要的是,arena 中的对象能够以起码的内存治理或垃圾回收开销一次开释所有内容。 arena 通常不会在具备垃圾回收的编程语言中实现,因为它们用于显式开释 arena 内存的操作并不平安,所以不合乎垃圾回收语义。 然而,此提案的实现应用了动静查看来确保 arena 操作是平安的。如果 arena 操作不平安,程序将在任何不正确的行为产生之前终止。 目前 Go 团队已在Google 外部应用了arena,结果显示 arena为许多大型应用程序节俭了高达 15% 的 CPU 和内存使用量,这次要是因为垃圾回收CPU 工夫和堆内存使用量的缩小。 提案介绍Go 团队试图在Go 规范库中增加一个新的 arena 包。arena 包将调配任意数量的 arena,能够从 arena 的内存中调配任意类型的对象,并且 arena 会依据须要主动增长大小。 当一个 arena 中的所有对象不再应用时,能够显式开释该 arena 以无效地回收其内存,而无需进行个别的垃圾回收操作。Go 团队要求此实现提供安全检查,如果 arena操作不平安,程序将在任何不正确的行为产生之前终止。为了取得最大的灵活性,API 可能调配任何类型的对象和切片,包含能够在运行时通过反射生成的类型。 提案 APIpackage arenatype Arena struct { // contains filtered or unexported fields}// New allocates a new arena.func New() *Arena// Free frees the arena (and all objects allocated from the arena) so that// memory backing the arena can be reused fairly quickly without garbage// collection overhead.  Applications must not call any method on this// arena after it has been freed.func (a *Arena) Free()// New allocates an object from arena a.  If the concrete type of objPtr is// a pointer to a pointer to type T (**T), New allocates an object of type// T and stores a pointer to the object in *objPtr.  The object must not// be accessed after arena a is freed.func (a *Arena) New(objPtr interface{})// NewSlice allocates a slice from arena a.  If the concrete type of slicePtr// is *[]T, NewSlice creates a slice of element type T with the specified// capacity whose backing store is from the arena a and stores it in// *slicePtr. The length of the slice is set to the capacity.  The slice must// not be accessed after arena a is freed.func (a *Arena) NewSlice(slicePtr interface{}, cap int)用法示例: import ( “arena” …)type T struct { val int}func main() { a := arena.New() var ptrT *T a.New(&ptrT) ptrT.val = 1 var sliceT []T a.NewSlice(&sliceT, 100) sliceT[99] .val = 4 a.Free()}

March 2, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法数学x-的平方根二分法

题目:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 因为返回类型是整数,后果只保留 整数局部 ,小数局部将被 舍去 。 留神:不容许应用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。 链接: 力扣Leetcode—中级算法—数学—x 的平方根. 示例 1: 输出:x = 4输入:2示例 2: 输出:x = 8输入:2解释:8 的算术平方根是 2.82842..., 因为返回类型是整数,小数局部将被舍去。标签:数学、二分查找 思路:通过 二分查找法 取得后果,下届为0,上届设定为x,在二分查找的每一步中,都须要比拟两头元素mid的平方与x的大小关系,并通过比拟的后果调整上下界的范畴。最初当下届大于上届完结,取得答案。 全副Go代码如下: package mainimport "fmt"func mySqrt(x int) int { l, r := 0, x res := 0 for l <= r { mid := l + (r-l)/2 if mid*mid <= x { res = mid l = mid + 1 } else { r = mid - 1 } } return res}func main() { fmt.Println(mySqrt(4))}提交截图: ...

March 2, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法数学Powx-n分治算法

题目:实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn )。 链接: 力扣Leetcode—中级算法—数学—Pow(x, n). 示例 1: 输出:x = 2.00000, n = 10输入:1024.00000示例 2: 输出:x = 2.10000, n = 3输入:9.26100示例 3: 输出:x = 2.00000, n = -2输入:0.25000解释:2-2 = 1/22 = 1/4 = 0.25标签:递归、数学 思路:咱们能够应用连乘的办法进行计算,如果n是负数求n次x相乘的后果即可,如果n为正数则求1/x相乘的后果,然而,这样做有的状况下必定会超时。测试如下: func myPow(x float64, n int) float64 { if n == 0 { return 1 } if n < 0 { x = 1 / x n = -n } res := x for i := 1; i < n; i++ { res *= x } return res}果不其然,超时了咱们能够用 疾速幕+递归 的办法,「疾速幕算法」的实质是 分治算法 。 ...

March 1, 2022 · 2 min · jiezi

关于golang:golangleetcode专项训练数组与切片

概念在golang中,数组和切片是两个概念 数组数组是一个由固定长度的特定类型元素组成的序列,一个数组能够由零个或多个元素组成。 能够应用len()函数获取数组的长度 切片因为数组的长度是固定的,因而在Go语言中很少间接应用数组。和数组对应的类型是Slice(切片),它是能够增长和膨胀的动静序列,slice性能也更灵便。 除了长度,切片多了容量属性,能够通过应用内置的 len()函数求长度,应用内置的cap()函数求容量。 雷同都能够间接通过下标的形式拜访元素 区别初始化数组 a := [3]int{1,2,3} //指定长度//ora := [...]int{1,2,3} //不指定长度//ora := [...]int{99: -1}//指定初始化,只有最初一个元素初始化为-1,其余为0数组能够拓展到多维数组 // 申明一个二维整型数组,两个维度的长度别离是 4 和 2var array [4][2]int// 应用数组字面量来申明并初始化一个二维整型数组array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}// 申明并初始化数组中索引为 1 和 3 的元素array = [4][2]int{1: {20, 21}, 3: {40, 41}}// 申明并初始化数组中指定的元素array = [4][2]int{1: {0: 20}, 3: {1: 41}}切片 s := make([]int) //创立一个长度为0,容量为0的切片s := make([]int, 3, 5)//指定长度和容量//ors := []int{1,2,3} //不指定长度切片同样能够拓展到多维切片 //申明一个二维切片var slice [][]int//为二维切片赋值slice = [][]int{{10}, {100, 200}}增加元素尽管数组在初始化时也能够不指定长度,但 Go 语言会依据数组中元素个数主动设置数组长度,并且不可扭转。 ...

March 1, 2022 · 1 min · jiezi

关于golang:网站在线客服系统GOFLY源码开发日志-2-开发命令行应用

我始终以来都是做 PHP 开发,除非是应用 swoole 框架,大部分 PHP 利用都是把代码传到服务器对应的目录里,启动 nginx+php-fpm 来运行 PHP 代码。 golang 和 PHP 是不一样的,golang 能够作为一个后端的服务监听端口来运行,这个时候就要能在命令行中启动和传递参数。 选用 github.com/spf13/cobra 这个库来解决命令行参数的解析。能够通过命令行把想要执行的不同动作辨别开,不同的动作外面又要传递不同的参数 比方我实现的性能是 ./go-fly-pro server 是开启监听端口服务,./go-fly-pro install 是导入数据库的脚本,这个就是命令行的第二个参数辨别不同的动作 命令的第三个到最初的参数是传递不同的配置参数,我实现了./go-fly-pro server -p 端口号 ,能够配置监听不同的端口,这就是命令行利用的次要逻辑。 入口文件是 go-fly.go ,外面就是间接调用 cmd 包的 Execute 办法 package mainimport ( "go-fly-muti/cmd" )func main() { cmd.Execute()}自定义的 cmd 包就是命令行利用的性能包,有入口办法,有全局变量,有初始化动作 每个动作都是一个 cobra.Command 构造实体 package cmdimport ( "github.com/spf13/cobra" "log" "os" ) var rootCmd = &cobra.Command{ Use: "go-fly-pro", Short: "go-fly-pro", Long: `简洁疾速的GO语言在线客服零碎GOFLY`,}func init() { rootCmd.AddCommand(serverCmd) rootCmd.AddCommand(installCmd) rootCmd.AddCommand(stopCmd) rootCmd.AddCommand(indexCmd)}func Execute() { if err := rootCmd.Execute(); err != nil { log.Println("执行命令参数谬误:", err) os.Exit(1) }}这就是命令行入口文件,前面还遇到了哪些问题和知识点将会持续进行总结。 ...

March 1, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法数学Excel表列序号

题目:给你一个字符串 columnTitle ,示意 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如: A -> 1B -> 2C -> 3...Z -> 26AA -> 27AB -> 28 ... 链接: 力扣Leetcode—中级算法—数学—Excel表列序号. 示例 1: 输出: columnTitle = "A"输入: 1示例 2: 输出: columnTitle = "AB"输入: 28示例 3: 输出: columnTitle = "ZY"输入: 701标签:数学、字符串 思路:题目意思: 位数位值个位AA = 1十位AA = 1 * 26百位AA = 1 26 26个位BB = 2十位BB = 2 * 26百位BB = 2 26 26......输入 = 个位 + 十位 + 百位 ...

March 1, 2022 · 1 min · jiezi

关于golang:golang中的单元测试

优良的代码习惯肯定是随同着单元测试的,这也是go语言设计的哲学; 国外的很多公司很多优良的程序员都比拟器重TDD,然而在国内非常少见;(TDD:测试驱动开发(test driven devlopment)) 无论如何,学习并应用golang的单元测试,不是浪费时间,而是让你的代码更加优雅健硕! 测试文件文件名以_test.go为后缀的文件均为测试代码,都会被go test测试捕获,不会被go build编译; 测试函数测试文件中的三种函数类型: 单元测试函数:函数名前缀Test;测试程序的逻辑基准函数:函数名前缀Benchmark;测试函数的性能示例函数:函数名前缀Example;会呈现在godoc中的,为文档提供示例文档测试命令Go语言中的测试依赖go test命令;在此命令下增加各种不同的参数以实现不同目标的测试;前面会一一介绍; go test命令会遍历所有的*_test.go文件中合乎上述命名规定的测试函数; 而后生成一个长期的main包用于调用相应的测试函数,而后构建并运行、报告测试后果,最初清理测试中生成的临时文件; 接下来别离介绍单元测试函数、基准函数、示例函数: 单元测试函数单元测试函数的格局: func TestName(t *testing.T) {}函数的名字必须以Test结尾,可选的后缀名必须以大写字母结尾每个测试函数必须导入testing包;对于testing包中的办法能够去看一下源码;参数t用于报告测试失败和附加的日志信息一个简略的测试函数示例:将输入的后果与预期的后果进行比拟 创立业务函数 // 文件split/split.go:定义一个split的包,包中定义了一个Split函数package splitimport "strings"func Split(s, sep string) (result []string) { i := strings.Index(s, sep) for i > -1 { result = append(result, s[:i]) s = s[i+1:] i = strings.Index(s, sep) } result = append(result, s) return}创立测试文件 // 文件split/split_test.go:创立一个split_test.go的测试文件package splitimport ( "reflect" "testing")// 单元测试函数// 测试函数名必须以Test结尾,必须接管一个*testing.T类型参数// 1. 间接调用业务函数// 2. 定义冀望后果// 3. 比拟理论后果和冀望后果func TestSplit(t *testing.T) { got := Split("a:b:c", ":") // 调用程序并返回程序后果 want := []string{"a", "b", "c"} // 冀望的后果 if !reflect.DeepEqual(want, got) { // 因为slice不能间接比拟,借助反射包中的办法比拟 t.Errorf("expected:%v, got:%v", want, got) // 如果测试失败输入谬误提醒 }}// 提供一个失败的单元测试func TestSplitFail(t *testing.T) { got := Split("abcd", "bc") want := []string{"a", "d"} if !reflect.DeepEqual(want, got) { t.Errorf("expected:%v, got:%v", want, got) }}// 基准测试函数func BenchmarkSplit(b *testing.B) {}// 示例函数func ExampleSplit() {}执行测试命令 ...

March 1, 2022 · 3 min · jiezi

关于golang:第三十一期360后台开发实习面经-两轮技术面

一面 自我介绍我的项目相干应用 database/sql 和应用 gorm 的区别为什么要应用 redis 连接池基础知识过程/线程/协程的区别面向对象的三大个性 (联合 Go 说说)如何限度 goroutine 并发数目:channel 或 WaitGroup发问环节Go 开发能够补充什么常识:高并发/分布式性能监控/性能优化单元测试/压力测试动静调试二面算法相关 (PS: 没有手撕,只讲思路) LeetCode-104 二叉树的最大深度LeetCode-110 均衡二叉树基础知识Go 高并发和分布式的特点Go 如何查看性能:pprofGo 如何进行调试:gdb/delveGo 如何打印堆栈:runtime.Caller谈谈对 Web 框架的了解(联合 gin 说说)Redis 的数据类型和底层实现谈谈对 Docker 容器的了解Linux 的命名空间是什么Linux 命令应用:查看过程:ps/top查看内存:free查看磁盘:df/du发问环节对本次面试的评估:多去了解底层常识。总结:侧重于 Go 工程治理的常识(可能和组里做平安无关),尽管没有通过第一次的面试也学到很多啦!

March 1, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法数学阶乘后的零

题目:给定一个整数 n ,返回 n! 后果中尾随零的数量。 提醒 n! = n (n - 1) (n - 2) ... 3 2 1 链接: 力扣Leetcode—中级算法—数学—阶乘后的零. 示例 1: 输出:n = 3输入:0解释:3! = 6 ,不含尾随 0示例 2: 输出:n = 5输入:1解释:5! = 120 ,有一个尾随 0示例 3: 输出:n = 0输入:0标签:数学 谬误思路:大家一开始想到的办法大多是一边计算阶乘,一边计算零的个数的办法,然而这种办法就算不报错也会超时。就是当数n大了当前,可能会超出int类型的示意范畴,可能会导致后果变为正数或者因溢出而造成的截断误差。 谬误Go代码如下: package mainimport ( "fmt")func trailingZeroes(n int) int { if n <= 0 { return 0 } res := 1 for i := 1; i <= n; i++ { res *= i } sum := 0 for res != 0 { a := res % 10 if a == 0 { sum++ } else { break } res /= 10 } return sum}func main() { fmt.Println(trailingZeroes(30))}当输出为30时,当乘到22,res就变成了正数,导致谬误:正确思路:咱们能够想在什么状况下乘积的开端会是零,天然就是因数蕴含了相似于10这种本身带有0的数和相似于5这种本身蕴含5的数 ...

February 28, 2022 · 1 min · jiezi

关于golang:Leetcode专题字符串151翻转字符串里的单词

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题如果独自开拓空间,比拟好解如果原地进行实现,那么就比拟有难度,须要技巧,这里应用双指针的解法,先去除冗余空格而后进行两次翻转,首先全字符串翻转,而后针对单词翻转,翻转的翻转就是原文func reverseWords(s string) string { b := []byte(s) // 外围解法:两次翻转,首先进行整体的翻转,而后单词翻转复位,能够实现原地操作 // 1、定义快慢指针,进行去处多余空格的操作 fastIndex, slowIndex := 0, 0 // 2、首先移除字符串首部的空格 for len(b) > 0 && fastIndex < len(b) && b[fastIndex] == ' ' { fastIndex++ } // 3、移除字符串两头的冗余空格 for ; fastIndex < len(b); fastIndex++ { if fastIndex - 1 > 0 && b[fastIndex - 1] == b[fastIndex] && b[fastIndex] == ' ' { continue } b[slowIndex] = b[fastIndex] slowIndex++ } // 4、移除字符串末端的冗余空格 if slowIndex > 0 && b[slowIndex-1] == ' ' { b = b[:slowIndex - 1] } else { b = b[:slowIndex] } // 5、整体翻转 reverse(&b, 0, len(b)-1) // 6、遍历分单词翻转 i := 0 for i < len(b) { j := i for ; j < len(b) && b[j] != ' '; j++ { } reverse(&b, i, j-1) i = j i++ } return string(b)}func reverse(b *[]byte, low, high int) { for low <= high { (*b)[low], (*b)[high] = (*b)[high], (*b)[low] low++ high-- }}

February 28, 2022 · 1 min · jiezi

关于golang:Leetcode专题字符串剑指-Offer-05替换空格

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题如果新增空间,就比较简单如果须要原地替换,那么能够应用两个指针,首先统计有多少个空格,因为每个空格替换后会多进去两个byte,所以依照这个数字进行扩容,而后从原字符串尾部进行遍历,遇到空格替换填入func replaceSpace(s string) string { b := []byte(s) spaceCount := 0 for _, v := range b { if v == ' ' { spaceCount++ } } tmpSize := make([]byte, spaceCount * 2) // 每个空格换成%20减少两个大小 b = append(b, tmpSize...) i := len(s) - 1 j := len(b) - 1 for i >= 0 { if b[i] != ' ' { b[j] = b[i] i-- j-- } else { b[j] = '0' b[j-1] = '2' b[j-2] = '%' j = j-3 i = i-1 } } return string(b)}

February 28, 2022 · 1 min · jiezi

关于golang:Leetcode专题字符串541反转字符串II

力扣链接:https://leetcode-cn.com/probl...解题思路: 给定一个字符串 s 和一个整数 k,从字符串结尾算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。如果残余字符少于 k 个,则将残余字符全副反转。如果残余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符放弃原样。这道题其实就是还原题目,解法中有两个条件:(1)每计数2k个字符,那么符合条件,进行判断(2)判断的时候分为两个条件:如果间隔字符完结>=k个字符,那么翻转前k个字符,如果<k,那么翻转残余字符func reverseStr(s string, k int) string { n := len(s) bs := []byte(s) for i := 0; i < n; i += (2 * k) { if i + k <= n { reverse(bs[i:i+k]) } else { reverse(bs[i:n]) } } return string(bs)}func reverse(s []byte) { n := len(s) low, high := 0, n-1 for low <= high { s[low], s[high] = s[high], s[low] low++ high-- } }

February 28, 2022 · 1 min · jiezi

关于golang:Leetcode专题字符串344反转字符串

力扣链接:https://leetcode-cn.com/probl...解题思路: 翻转字符串这道题比较简单,应用两个指针,而后从首位开始遍历,替换首尾地位,循环直到首尾相遇func reverseString(s []byte) { n := len(s) low, high := 0, n-1 for low <= high { s[low], s[high] = s[high], s[low] low++ high-- }}

February 28, 2022 · 1 min · jiezi

关于golang:第三十期shopee-golang开发一面面经

一面全副问根底,答得不好,在这里记录一下,攒攒人品。 有环链表 一个有环的链表,如何确认链表有环,环的长度。hashmap 设计一个hashmap,你要用什么数据结构 能用数组能做为存储hashmap的数据结构吗?不能的话,要怎么做?怎么解决hash抵触 你的设计里怎么依据key查找对应的值mysql 事务 mysql事务的隔离级别有几种,别离论述 在串行化隔离级别中,怎么加读锁和写锁,这里的锁是什么锁:表锁?行锁?还是其余锁?mysql的索引 假如联结索引为<a,b,c> select * from table_name where c> 10 and a = 10 and b < 10 limit 2000,10 该语句有什么问题,如何优化Linux 操作相干 如何查看cpu占用 top命令中idle字段的解释 如何查看端口占用 如何查看文件操作权限 ls -al 中 每行前10个字符的意思 如何更改文件权限go 相干 介绍一下协程,协程和线程的关系 MPG模型 一个main函数内用go 开启多个协程,当初一个协程panic了,main函数会怎么?为什么?用户态和内核态tcp相干 tcp和udp协定的区别,tcp有而udp没有的特色有哪些 tcp中滑动窗口的原理,假如窗口1,2,3曾经发送,远端ack 4 ,这时候滑动窗口要向前挪动吗?为什么?http相干 http如何实现有状态连贯 cookie 和session的区别编程题 字符串加法:实现加法,然而输出和输入的数字都是字符串格局

February 28, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法数学快乐数快慢指针

题目:编写一个算法来判断一个数 n 是不是高兴数。 「高兴数」 定义为: 对于一个正整数,每一次将该数替换为它每个地位上的数字的平方和。而后反复这个过程直到这个数变为 1,也可能是 有限循环 但始终变不到 1。如果这个过程 后果为 1,那么这个数就是高兴数。如果 n 是 高兴数 就返回 true ;不是,则返回 false 。 链接: 力扣Leetcode—中级算法—数学—高兴数. 示例 1: 输出:n = 19输入:true解释:12 + 92 = 8282 + 22 = 6862 + 82 = 10012 + 02 + 02 = 1示例 2: 输出:n = 2输入:false标签:哈希表、数学、双指针 思路:一开始大家都会思考一个问题,如果始终没有失去1会陷入循环。为了解决这个问题,咱们能够用快慢指针,检测是否存在循环,如果快指针追上慢指针还没呈现1,证实不是高兴数;反之亦然 全副Go代码如下: package mainimport "fmt"func isHappy(n int) bool { // 如果始终没有失去1会陷入循环,所以咱们用快慢指针,检测是否存在循环,如果快指针等于慢指针还没呈现1,证实不是高兴数;反之亦然 slow := n fast := next(n) for fast != 1 && fast != slow { slow = next(slow) fast = next(next(fast)) } if fast == 1 { return true } return false}// 上一个数的和的数其每个地位上的数字的平方和func next(n int) int { sum := 0 for n != 0 { pop := n % 10 sum += pop * pop n /= 10 } return sum}func main() { fmt.Println(isHappy(19))}提交截图: ...

February 28, 2022 · 1 min · jiezi

关于golang:探讨系统中钱的精度问题

来自公众号:Gopher指北钱,乃亘古之玄物,有则气粗神壮,缺则心卑力浅在一个零碎中,特地是一个和钱相干的零碎,钱乃重中之重,计算时的精度将是本篇探讨的主题。 精度为何如此重要“积羽沉舟”用在此处最为适合。如果某电商平台每年订单成交数量为10亿,每笔订单少结算1分钱,则累计损失1000万!有一说一,这损失的钱就是王某人的十分之一个小指标。如果因为精度问题在给客户结算时,少算会损失客户,多算会损失钱。由此可见,准确的计算钱非常重要! 为什么会有精度的问题经典案例,咱们来看一下0.1 + 0.2在计算机中是否等于0.3。 上述case学过计算机的应该都晓得,计算机是二进制的,用二进制示意浮点数时(IEEE754规范),只有大量的数能够用这种办法准确的示意进去。上面以0.3为例看一下十进制转二进制小数的过程。 计算机的位数有限度,因而计算机用浮点数计算时必定无奈失去准确的后果。这种硬限度无奈冲破,所以须要引入精度以保障对钱的计算在容许的误差范畴内尽可能精确。 对于浮点数在计算机中的理论示意本文不做进一步探讨,能够参考下述连接学习: 单精度浮点数示意: https://en.wikipedia.org/wiki... 双精度浮点数示意: https://en.wikipedia.org/wiki... 浮点数转换器: https://www.h-schmidt.net/Flo... 用浮点数计算还是以上述0.1 + 0.2为例,0.00000000000000004的误差齐全能够疏忽,咱们尝试小数局部保留5位精度,看上面后果。 此时的后果合乎预期。这也是为什么很多时候判断两个浮点数是否相等往往采纳a - b <= 0.00001的模式,说白了这就是小数局部保留5位精度的另一种表现形式。 用整型计算后面提到只有大量的浮点数能够用IEEE754规范示意,而整型可准确示意所有无效范畴内的数。因而很容易想到,应用整型示意浮点数。 例如,当时定好小数保留8位精度,则0.1和0.2别离示意成整数为10000000和20000000, 浮点数的运算也就转换为整型的运算。还是以0.1 + 0.2为例。 // 示意小数位保留8位精度const prec = 100000000func float2Int(f float64) int64 { return int64(f * prec)}func int2float(i int64) float64 { return float64(i) / prec}func main() { var a, b float64 = 0.1, 0.2 f := float2Int(a) + float2Int(b) fmt.Println(a+b, f, int2float(f)) return}上述代码输入后果如下: ...

February 27, 2022 · 2 min · jiezi

关于golang:Go进阶并发编程RWMutex

规范库中的 RWMutex 是一个 reader/writer 互斥锁。RWMutex 在某一时刻只能由任意数量的 reader 持有,或者是只被单个的 writer 持有。RWMutex 的办法也很少,总共有 5 个: Lock/Unlock:写操作时调用的办法。如果锁曾经被 reader 或者 writer 持有,那么,Lock 办法会始终阻塞,直到能获取到锁;Unlock 则是配对的开释锁的办法。RLock/RUnlock:读操作时调用的办法。如果锁曾经被 writer 持有的话,RLock 办法会始终阻塞,直到能获取到锁,否则就间接返回;而 RUnlock 是 reader 开释锁的办法。RLocker:这个办法的作用是为读操作返回一个 Locker 接口的对象。它的 Lock 办法会调用 RWMutex 的 RLock 办法,它的 Unlock 办法会调用 RWMutex 的 RUnlock 办法。如果你遇到能够明确辨别 reader 和 writer goroutine 的场景,且有大量的并发读、大量的并发写,并且有强烈的性能需求,就能够思考应用读写锁 RWMutex 替换 Mutex。 实现原理读写锁设计方案基于对读和写操作的优先级,读写锁的设计和实现能够分成三类: Read-preferring:读优先的设计能够提供很高的并发性,然而在竞争强烈的状况下可能会导致写饥饿。Write-preferring:写优先的设计意味着,如果曾经有一个 writer 在期待申请锁的话,它会阻止新来的申请锁的 reader 获取到锁,所以优先保障 writer。不指定优先级:这种设计比较简单,不辨别 reader 和 writer 优先级,某些场景下这种不指定优先级的设计反而更无效。Go 规范库中的 RWMutex 设计是 Write-preferring 计划,一个正在阻塞的 Lock 调用会排除新的 reader 申请到锁。 ...

February 27, 2022 · 2 min · jiezi

关于golang:golangleetcode中级任务调度器

题目 解题思路两个 雷同品种 的工作之间必须有长度为整数 n 的冷却工夫,因而执行工作的工夫将由工作将其冷却工夫决定,雷同品种的工作数量越多,其冷却工夫也就越长,为了使总体工夫缩短,咱们应该更早的让其进入冷却工夫 外围思路:就是先找出雷同元素数量最大的元素A 咱们将执行一个工作及其冷却工夫的期待看作一个周期那么 实现工作A的总工夫就等于(a-1)个周期加上最初一次执行即可实现A工作对于剩下的工作咱们能够进行分类探讨 如果其余工作都能够在A 的冷却工夫内实现,那么总工夫即为A所应用的工夫,其余工作能够忽略不计。 如果A的冷却工夫内放不下其余的所有工作,那么则将工夫较长的放入,残余的另行计算1.如果剩下的雷同品种的工作中数量有与A并列第一的那么最初一次执行工作的时候,也须要执行这个工作一次2.其余工作长度都比A少,但数量很多,再实现A 的计算之后反复即可 代码func leastInterval(tasks []byte, n int) int { max:=func(x,y int)int{ if x<y{ return y } return x } tmp,res:=make(map[byte]int,0),0 for _,v:=range tasks{ tmp[v]++ } ans:=0 for _,v:=range tmp{ ans = max(ans,v) } res = (ans-1)*(n+1) for _,v:=range tmp{ if v==ans{ res++ } } if len(tasks)<=res{ return res } return len(tasks)}作者:Johnny-Young链接:https://leetcode-cn.com/problems/task-scheduler/solution/tan-xin-by-yhemin/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。复杂度剖析 ovo不太了解官解

February 27, 2022 · 1 min · jiezi

关于golang:Go进阶并发编程Mutex

互斥锁是并发程序中对临界资源进行访问控制的最根本伎俩,Mutex 即为 Go 语言原生的互斥锁实现。 数据结构源码包 src/sync/mutex.go 中定义了 Mutex 的数据结构: type Mutex struct { state int32 sema uint32}state 字段示意互斥锁的状态,是 32 位的整型,外部实现时把该变量分成四局部,用于记录四种状态: Locked: 示意该互斥锁是否已被锁定;Woken: 示意是否从失常模式被唤醒;Starving:示意该Mutex是否处于饥饿状态;Waiter: 示意互斥锁上阻塞期待的协程个数。sema 字段示意信号量,加锁失败的协程阻塞期待该信号量,解锁的协程开释信号量从而唤醒期待信号量的协程。 失常模式和饥饿模式Mutex 有两种模式——失常模式和饥饿模式,饥饿模式是 1.9 版本中引入的优化,目标是保障互斥锁的公平性,避免协程饿死。默认状况下,Mutex 的模式为失常模式。 在失常模式下,协程如果加锁不胜利不会立刻转入期待队列,而是判断是否满足自旋的条件,如果满足则会自旋。 当持有锁的协程开释锁的时候,会开释一个信号量来唤醒期待队列中的一个协程,但如果有协程正处于自旋过程中,锁往往会被该自旋协程获取到。被唤醒的协程只好再次阻塞,不过阻塞前会判断自上次阻塞到本次阻塞通过了多长时间,如果超过 1ms 的话,会将 Mutex 标记为饥饿模式。 在饥饿模式下,新加锁的协程不会进入自旋状态,它们只会在队列的开端期待,互斥锁被开释后会间接交给期待队列最后面的协程。如果一个协程取得了互斥锁并且它在队列的开端或者它期待的工夫少于 1ms,那么互斥锁就会切换回失常模式。 办法互斥锁 Mutex 就提供两个办法 Lock 和 Unlock:进入临界区之前调用 Lock 办法,退出临界区的时候调用 Unlock 办法。 Lockfunc (m *Mutex) Lock() { if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) { return } m.lockSlow()}当锁的状态是 0 时,将 mutexLocked 置成 1,这是最简略的状况。如果互斥锁的状态不是 0 时就会调用 lockSlow 办法,这里将它分成几个局部介绍获取锁的过程: ...

February 27, 2022 · 4 min · jiezi

关于golang:官方教程Go-fuzzing模糊测试

前言Go 1.18在go工具链里引入了fuzzing含糊测试,能够帮忙咱们发现Go代码里的破绽或者可能导致程序解体的输出。Go官网团队也在官网公布了fuzzing入门教程,帮忙大家疾速上手。 自己对Go官网教程在翻译的根底上做了一些表述上的优化,以飨读者。 留神:fuzzing含糊测试和Go已有的单元测试以及性能测试框架是互为补充的,并不是代替关系。 教程内容这篇教程会介绍Go fuzzing的入门基础知识。fuzzing能够结构随机数据来找出代码里的破绽或者可能导致程序解体的输出。通过fuzzing能够找出的破绽包含SQL注入、缓冲区溢出、拒绝服务(Denial of Service)攻打和XSS(cross-site scripting)攻打等。 在这个教程里,你会给一个函数写一段fuzz test(含糊测试)程序,而后运行go命令来发现代码里的问题,最初通过调试来修复问题。 本文里波及的专业术语,能够参考 Go Fuzzing glossary。 接下来会依照如下章节介绍: 为你的代码创立一个目录实现一个函数减少单元测试减少含糊测试修复2个bug总结筹备工作装置Go 1.18 Beta 1或者更新的版本。装置指引能够参考上面的介绍。有一个代码编辑工具。任何文本编辑器都能够。有一个命令行终端。Go能够运行在Linux,Mac上的任何命令行终端,也能够运行在Windows的PowerShell或者cmd之上。有一个反对fuzzing的环境。目前Go fuzzing只反对AMD64和ARM64架构。装置和应用beta版本这个教程须要应用Go 1.18 Beta 1或以上版本的泛型性能。应用如下步骤,装置beta版本 应用上面的命令装置beta版本 $ go install golang.org/dl/go1.18beta1@latest运行如下命令来下载更新 $ go1.18beta1 download留神:如果在MAC或者Linux上执行go1.18beta1提醒command not found,须要设置bash或者zsh对应的profile环境变量文件。bash设置在~/.bash_profile文件里,内容为: export GOROOT=/usr/local/opt/go/libexecexport GOPATH=$HOME/goexport PATH=$PATH:$GOROOT/bin:$GOPATH/binGOROOT和GOPATH的值能够通过go env命令查看,设置完后执行source ~/.bash_profile让设置失效,再执行go1.18beta1就不报错了。 应用beta版本的go命令,不要去应用release版本的go命令 你能够通过间接应用go1.18beta1命令或者给go1.18beta1起一个简略的别名 间接应用go1.18beta1命令 $ go1.18beta1 version给go1.18beta1命令起一个别名 $ alias go=go1.18beta1$ go version上面的教程都假如你曾经把go1.18beta1命令设置了别名go。 为你的代码创立一个目录首先创立一个目录用于寄存你写的代码。 关上一个命令行终端,切换到你的home目录 在Linux或者Mac上执行如下命令(Linux或者Mac上只须要执行cd就能够进入到home目录) cd在Windows上执行如下命令 C:\> cd %HOMEPATH%在命令行终端,创立一个名为fuzz的目录,并进入该目录 $ mkdir fuzz$ cd fuzz创立一个go module 运行go mod init命令,来给你的我的项目设置module门路 $ go mod init example/fuzz留神:对于生产代码,你能够依据我的项目理论状况来指定module门路,如果想理解更多,能够参考Go Module依赖治理。 ...

February 27, 2022 · 6 min · jiezi

关于golang:LRU和LFU-算法页面置换算法

LRU和LFU的区别LRU和LFU都是内存治理的页面置换算法。 LRU:最近起码应用(最长工夫)淘汰算法(Least Recently Used)。LRU是淘汰最长工夫没有被应用的页面。 LFU:最不常常应用(起码次)淘汰算法(Least Frequently Used)。LFU是淘汰一段时间内,应用次数起码的页面。 例子 假如LFU办法的期间T为10分钟,拜访如下页面所花的工夫正好为10分钟,内存块大小为3。若所需页面程序顺次如下: 2 1 2 1 2 3 4 ----------------------------------------> 当须要应用页面4时,内存块中存储着1、2、3,内存块中没有页面4,就会产生缺页中断,而且此时内存块已满,须要进行页面置换。若按LRU算法,应替换掉页面1。因为页面1是最长工夫没有被应用的了,页面2和3都在它前面被应用过。若按LFU算法,应换页面3。因为在这段时间内,页面1被拜访了2次,页面2被拜访了3次,而页面3只被拜访了1次,一段时间内被拜访的次数起码。LRU 要害是看页面最初一次被应用到产生替换的工夫长短,工夫越长,页面就会被置换; LFU要害是看肯定时间段内页面被应用的频率(次数),应用频率越低,页面就会被置换。 LRU算法适宜:较大的文件比方游戏客户端(最近加载的地图文件);LFU算法适宜:较小的文件和系统的文件比方系统文件、应用程序文件 ;LRU耗费CPU资源较少,LFU耗费CPU资源较多。LRU (最长工夫)最近最久未应用算法, LRU是淘汰最长工夫没有被应用的页面性能缓存容量capacity为正整数,缓存的key、value均为int类型读缓存func get(key int) int: key已存在,返回对应valuekey不存在,返回-1写缓存func put(key int, value int): key已存在,批改对应valuekey不存在,写入该组缓存,若写入前缓存容量已达下限,则应淘汰最久未应用的缓存(强调:读、写缓存均视为应用)数据结构应用双向链表保护缓存的上一次应用工夫: 约定:链表正方向(从头部到尾部)节点依照应用工夫排序——越早应用(即久未应用)的节点,越凑近链表尾部保护:每应用一次缓存,就将该缓存对应的链表节点挪动到链表头部;缓存淘汰时,只须要删除尾部节点即可减少一个map,记录key到链表节点的映射关系; 解决如果只应用双向链表,每次判断key是否存在时,都要遍历链表cache:map[int]*listNode,key到节点的映射; 其中 listNode data:key, valuelist:*listNode,双向链表,保护缓存的上一次应用工夫capacity:int,链表容量伪代码读缓存 key存在: 在原链表中删除该缓存节点,从新插入到链表头部,返回对应的valuekey不存在: 返回-1写缓存(更新缓存) Key存在: 更新缓存节点的value值在原链表中删除该缓存节点,并把该从新插入到链表头部Key不存在: 容量已达下限: 在链表中删除尾部节点(记录该节点的key)依据上一步中记录的key,删除对应的映射关系依据输出参数结构新的节点:将新的节点插入链表头部新增key到新的节点的映射关系容量未达下限: 依据输出参数结构新的节点:将新的节点插入链表头部新增key到新的节点的映射关系Golang代码实现// 双向链表节点type doublyListNode struct { key int value int prev *doublyListNode next *doublyListNode}// 结构一个双向空链表(首尾几点都是空节点)func newDoublyList() *doublyListNode { headNode := &doublyListNode{} tailNode := &doublyListNode{} headNode.next = tailNode tailNode.prev = headNode return headNode}// 把节点增加到链表头部func (dl *doublyListNode) addToHead(node *doublyListNode) { dl.next.prev = node node.next = dl.next dl.next = node node.prev = dl}// 删除链表中的节点func removeNode(node *doublyListNode) { node.next.prev = node.prev node.prev.next = node.next}// LRUCache 具体的缓存type LRUCache struct { cache map[int]*doublyListNode head *doublyListNode tail *doublyListNode capacity int}// Constructor 构建缓存容器func Constructor(capacity int) LRUCache { dl := newDoublyList() return LRUCache{ cache: make(map[int]*doublyListNode), head: dl, tail: dl.next, capacity: capacity, }}func (lruCache *LRUCache) Get(key int) int { // 依据key 获取缓存 v, ok := lruCache.cache[key] // 如果没有缓存, 返回-1 if !ok { return -1 } // 如果有缓存 removeNode(v) // 移除该缓存 lruCache.head.addToHead(v) // 把缓存增加双向链表头部 return v.value}// Put 新建缓存func (lruCache *LRUCache) Put(key int, value int) { // 曾经有缓存 if v, ok := lruCache.cache[key]; ok { // v 是双链表中的节点 v.value = value // 更新链表节点中的值 lruCache.cache[key] = v // 更新缓存中映射关系 removeNode(v) // 移除该缓存 lruCache.head.addToHead(v) // 把缓存增加双向链表头部 return } // 缓存超长 淘汰缓存 if len(lruCache.cache) >= lruCache.capacity { node := lruCache.tail.prev removeNode(node) // 删除该节点 delete(lruCache.cache, node.key) // 革除 最近起码应用的缓存 } newNode := &doublyListNode{ key: key, value: value, } lruCache.cache[key] = newNode lruCache.head.addToHead(newNode)}LFU (起码次)性能缓存容量capacity、缓存的key和value均为自然数(能够为0,代码中独自解决)读缓存func get(key int) int:(与lru雷同) ...

February 27, 2022 · 4 min · jiezi

关于golang:golangleetcode中级多数元素

第一题 少数元素题目 简略的思路简略的想法是应用哈希表或者排序实现 遍历一次数组,将每个数呈现的次数存入哈希表,当次数大于n/2时返回即可然而该计划空间复杂度为O(n),不符合要求O(1) 将数组排成有序数组,计算每个元素呈现的次数,当次数大于n/2时返回即可然而排序的工夫复杂度为O(nlogn),大于题目要求O(n) 随机法 分治法 代码.3func majorityElement(nums []int) int { return majorityElementRec(nums, 0, len(nums) - 1)}//判断众数func countInRange(nums []int, target int,lo int, hi int) int{ count := 0 for i := lo; i <= hi; i++ { if nums[i] == target { count++ } } return count}//二分查找func majorityElementRec( nums []int, lo int, hi int) int{ //左边界等于右边界,只有一个元素,即为该数组众数 if lo == hi { return nums[lo] } mid := (lo + hi) / 2 //左右众数 leftMajority := majorityElementRec(nums, lo, mid) rightMajority := majorityElementRec(nums, mid + 1, hi) //返回真正的众数 if countInRange(nums, leftMajority, lo, hi) > (hi - lo + 1) / 2 { return leftMajority } if countInRange(nums, rightMajority, lo, hi) > (hi - lo + 1) / 2 { return rightMajority } return -1}摩尔投票法 ...

February 27, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法动态规划跳跃游戏

题目:给定一个非负整数数组 nums ,你最后位于数组的 第一个下标 。 数组中的每个元素代表你在该地位能够跳跃的最大长度。 判断你是否可能达到最初一个下标。 链接: 力扣Leetcode—中级算法—动静布局—跳跃游戏. 示例 1: 输出:nums = [2,3,1,1,4]输入:true解释:能够先跳 1 步,从下标 0 达到下标 1, 而后再从下标 1 跳 3 步达到最初一个下标。示例 2: 输出:nums = [3,2,1,0,4]输入:false解释:无论怎样,总会达到下标为 3 的地位。但该下标的最大跳跃长度是 0 , 所以永远不可能达到最初一个下标。标签:贪婪、数组、动静布局 思路: 咱们从前面往前面开始布局,能够必定的是,从最初一步到最初一步必定是能够达到的,所以bool数组的最初一个元素的值为true而后是后面的一个地位,那么要计算以后地位是否可能达到最初一个地位咱们只须要看从以后地位可能向后走的步数所达到的地位中是否存在可能达到最初一步的地位如果存在这样的地位,那么咱们就判断以后地位可能达到最初一步,如果不存在这样的地位,那么咱们断定以后地位不能到达最初的地位全副Go代码如下: package mainimport "fmt"func canJump(nums []int) bool { length := len(nums) - 1 for i := length - 1; i >= 0; i-- { if nums[i]+i >= length { length = i } } return length <= 0}func main() { a := []int{2, 3, 1, 1, 4} fmt.Println(canJump(a))}提交截图: ...

February 26, 2022 · 1 min · jiezi

关于golang:Go-Exec-僵尸与孤儿进程

原文地址:Go Exec 僵尸与孤儿过程 最近,应用 golang 去治理本地利用的生命周期,期间有几个乏味的点,明天就一起看下。 场景一咱们来看看上面两个脚本会产生什么问题: 创立两个 shell 脚本start.sh#!/bin/shsh sub.shsub.sh#!/bin/shn=0while [ $n -le 100 ]do echo $n let n++ sleep 1done执行脚本输入后果$ ./start.sh 012...过程关系查看过程信息 ps -jUSER PID PPID PGID SESS JOBC STAT TT TIME COMMANDroot 31758 31346 31758 0 1 S+ s000 0:00.00 /bin/sh ./start.shroot 31759 31758 31758 0 1 S+ s000 0:00.01 sh sub.shsub.sh 的 父过程(PPID)为 start.sh 的过程id(PID)sub.sh 和 start.sh 两个过程的 PGID 是同一个,( 属一个过程组)。删除 start.sh 的过程kill -9 31758# 再查看过程组ps -j## 返回USER PID PPID PGID SESS JOBC STAT TT TIME COMMANDroot 31759 1 31758 0 0 S s000 0:00.03 sh sub.shstart.sh 过程不在了sub.sh 过程还在执行sub.sh 过程的 PID 变成了 1问题1:那sub.sh 这个过程当初属于什么? ...

February 26, 2022 · 3 min · jiezi

关于golang:golangleetcode中级两整数之和逆波兰表达式求值

第一题 两整数之和题目 解题思路本题要求咱们实现加法 失去了编写代码过程中最根底的运算符咱们只能在更底层的实现中寻求帮忙 在数电中咱们学过半加器电路计算加法 半加器电路是指对两个输出数据位相加,输入一个后果位和进位,没有进位输出的加法器电路。 是实现两个一位二进制数的加法运算电路。半加器是通过异或门来具体实现的。凑巧,golang中^算符作为二元运算符的时候也提供了异或性能能够发现,对于整数 a 和 b: 在不思考进位的状况下,其无进位加法后果为 a⊕b。而所有须要进位的位为 a & b,进位后的进位后果为(a & b) << 1。 代码实现func getSum(a, b int) int { for b != 0 {//因为b存储低位的进位信号,将b设为循环终止条件 c := uint(a&b) << 1 a ^= b b = int(c) } return a}复杂度剖析工夫复杂度:O(log(max_int)),其中咱们将执行位运算视作原子操作。 空间复杂度:O(1)。 第二题 逆波兰表达式求值题目 思路逆波兰表达式的长处为咱们的解答提供了思路 应用栈实现求值计算 代码func evalRPN(tokens []string) int { stack := []int{} for _, token := range tokens { //读取字符 val, err := strconv.Atoi(token) if err == nil { //转换成数字胜利,是数字 stack = append(stack, val) } else { //是算符,取出两个数计算并将后果入栈 num1, num2 := stack[len(stack)-2], stack[len(stack)-1] stack = stack[:len(stack)-2] switch token { case "+": stack = append(stack, num1+num2) case "-": stack = append(stack, num1-num2) case "*": stack = append(stack, num1*num2) default: stack = append(stack, num1/num2) } } } return stack[0]}复杂度剖析 ...

February 26, 2022 · 1 min · jiezi

关于golang:golangleetcode中级分数到小数

题目 思路本题能够拆解为几个小问题解决 1.符号的计算 2.小数点前整数局部的计算 3.小数点后小数的计算 (1)无限的小数,当余数为零时进行计算(2)有限循环小数,当呈现反复的数字时,将循环局部退出字符串(3)有限不循环小数 ,因为分数为有理数,无需思考该类小数小数的具体计算方法能够应用竖式计算的长除法实现计算 代码func fractionToDecimal(numerator, denominator int) string { if numerator%denominator == 0 { return strconv.Itoa(numerator / denominator) } s := []byte{} if numerator < 0 != (denominator < 0) { s = append(s, '-') } // 整数局部 numerator = abs(numerator) denominator = abs(denominator) integerPart := numerator / denominator s = append(s, strconv.Itoa(integerPart)...) s = append(s, '.') // 小数局部 indexMap := map[int]int{} remainder := numerator % denominator for remainder != 0 && indexMap[remainder] == 0 { indexMap[remainder] = len(s) remainder *= 10 s = append(s, '0'+byte(remainder/denominator)) remainder %= denominator } if remainder > 0 { // 有循环节 insertIndex := indexMap[remainder] s = append(s[:insertIndex], append([]byte{'('}, s[insertIndex:]...)...) s = append(s, ')') } return string(s)}func abs(x int) int { if x < 0 { return -x } return x}复杂度剖析工夫复杂度:O(l),其中 l 是答案字符串的长度,这道题中 l≤10^4 。对于答案字符串中的每一个字符,计算工夫都是 O(1)。 ...

February 26, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表202快乐数

力扣链接:https://leetcode-cn.com/probl...解题思路: 编写一个算法来判断一个数 n 是不是高兴数。「高兴数」 定义为:(1)对于一个正整数,每一次将该数替换为它每个地位上的数字的平方和。(2)而后反复这个过程直到这个数变为 1,也可能是 有限循环 但始终变不到 1。(3)如果这个过程 后果为 1,那么这个数就是高兴数。(4)如果 n 是 高兴数 就返回 true ;不是,则返回 false 。重点一是求每个地位上的平方和,n%10求最初一位,n/10删除掉最初一位第二个重点是对于满足条件的判断,首先是循环,直到sum为1,或者sum中有反复值呈现阐明有循环,这个时候就须要哈希表来记录呈现过的sum值func isHappy(n int) bool { // 应用哈希表来判断 m := make(map[int]bool) for { sum := getSum(n) if sum == 1 { return true } if _, ok := m[sum]; ok { return false } m[sum] = true n = sum } return false}// 重点之一在于如何合成位数求均匀和,n%10求的以后数的最初一位,n/10删除最初一位func getSum(n int) int { sum := 0 for n != 0 { sum += (n%10) * (n%10) n = n / 10 } return sum}

February 26, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表349两个数组的交集

力扣链接:https://leetcode-cn.com/probl...解题思路: 给定两个数组 nums1 和 nums2 ,返回 它们的交加 。输入后果中的每个元素肯定是 惟一 的。咱们能够 不思考输入后果的程序两个数组的交加,实际上就是查找元素是否在两个数组中同时存在,查找元素思考应用哈希表这里每个元素输入一次即可,思考去重func intersection(nums1 []int, nums2 []int) []int { // 应用哈希表,并且反复交加数字只输入一次 m1 := make(map[int]bool, len(nums1)) for _, v := range nums1 { m1[v] = true } var res []int for _, v := range nums2 { if _, ok := m1[v]; ok && m1[v] { res = append(res, v) m1[v] = false } } return res}

February 26, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表242有效的字母异位词

力扣链接:https://leetcode-cn.com/probl...解题思路: 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词,留神:若 s 和 t 中每个字符呈现的次数都雷同,则称 s 和 t 互为字母异位词这里的异位词,其实就是不同单词之间的字母数都雷同,条件外面s和t都只蕴含小写字母查找某个元素是否存在,以及元素呈现的个数,能够应用哈希表来实现同时这道题也有一个非凡条件,那就是所有字母都是小写的,数组其实也是一种哈希表,所有字母都是小写的状况下,这个哈希表的个数是确定的,也就是26个,所以能够应用数组来代替,因为map的查找更加耗时,并且也更耗内存func isAnagram(s string, t string) bool { // 应用数组初始化26个字母 record := make([]int, 26) // 遍历s for i := 0; i < len(s); i++ { record[s[i] - 'a'] += 1 } for j := 0; j < len(t); j++ { record[s[j] - 'a'] -= 1 } for k := 0; k < len(record); k++ { if record[k] != 0 { return false } } return true}

February 26, 2022 · 1 min · jiezi

关于golang:Golang中关于Panic的俩点注意事项

在日常开发中一不小心程序就会呈现panic,如果没有注册recover,panic会间接中断程序前面的逻辑,使用不当会带来微小的隐患。上面小老虎就来介绍俩点对于panic的常见谬误! 一、Panic与Recover在并发问题中,咱们经常应用读写锁来保障并发的安全性。在内存透露的七种场景中咱们提到锁的使用不当,会使得groutine因获取不到锁,而导致内存透露。上面以超超和婷婷获取电视使用权为例。 定义电视构造体并提供注册和获取以后使用者的办法 type Television struct { belong string sync.RWMutex}func (m *Television) set(name string) { m.Lock() m.belong = name m.Unlock()}func (m *Television) get() string { m.RLock() user := m.belong m.RUnlock() return user}主过程中用户并发获取电视机使用权 func main() { users := []string{"chaochao", "tingting"} tv := &Television{} w := sync.WaitGroup{} usersLen := len(users) w.Add(usersLen) for i := 0; i < usersLen; i++ { go func(user string) { tv.set(user) w.Done() }(users[i]) } w.Wait() fmt.Println("TV user is", tv.get())}输入后果 ...

February 26, 2022 · 1 min · jiezi

关于golang:GM到GMPGolang经历了什么

超超和面试官聊完了协程的发展史之后,面试官仿佛想在GMP模型上对超超“痛下杀手”,上面来看超超能不能接住面试官的大杀器吧! GM模型面试官:你晓得GMP之前用的是GM模型吗?超超:这个我晓得,在12年的go1.1版本之前用的都是GM模型,然而因为GM模型性能不好,饱受用户诟病。之后官网对调度器进行了改良,变成了咱们当初用的GMP模型。 面试官:那你能给我说说什么是GM模型?为什么效率不好呢?考点:GM模型超超:GM模型中的G全称为Goroutine协程,M全称为Machine内核级线程,调度过程如下M(内核线程)从加锁的Goroutine队列中获取G(协程)执行,如果G在运行过程中创立了新的G,那么新的G也会被放入全局队列中。很显然这样做有俩个毛病,一是调度,返回G都须要获取队列锁,造成了强烈的竞争。二是M转移G没有把资源最大化利用。比方当M1在执行G1时,M1创立了G2,为了继续执行G1,须要把G2交给M2执行,因为G1和G2是相干的,而寄存器中会保留G1的信息,因而G2最好放在M1上执行,而不是其余的M。 GMP面试官:那你能给我说说GMP模型是怎么设计的吗?考点:GMP设计超超:G全称为Goroutine协程,M全称为Machine内核级线程,P全称为Processor协程运行所需的资源,他在GM的根底上减少了一个P层,上面咱们来看一下他是如何设计的。全局队列:当P中的本地队列中有协程G溢出时,会被放到全局队列中。P的本地队列:P内置的G队列,存的数量无限,不超过256个。这里有俩种非凡状况。一是当队列P1中的G1在运行过程中新建G2时,G2优先寄存到P1的本地队列中,如果队列满了,则会把P1队列中一半的G挪动到全局队列。二是如果P的本地队列为空,那么他会先到全局队列中获取G,如果全局队列中也没有G,则会尝试从其余线程绑定的P中偷取一半的G。 面试官:P和M数量是能够有限扩增的吗?考点:GMP细节超超:是不能有限扩增的,有限扩增零碎也接受不了呀,哈哈P的数量:由启动时环境变量$GOMAXPROCS或者是由runtime的办法GOMAXPROCS()决定。M的数量:go程序启动时,会设置M的最大数量,默认10000。然而内核很难创立出如此多的线程,因而默认状况下M的最大数量取决于内核。也能够调用runtime/debug中的SetMaxThreads函数,手动设置M的最大数量。 面试官:那P和M都是在程序运行时就被创立好了吗?考点:持续深挖GMP细节超超:P和M创立的机会是不同的P何时创立:在确定了P的最大数量n后,运行时零碎会依据这个数量创立n个P。M何时创立:内核级线程的初始化是由内核治理的,当没有足够的M来关联P并运行其中的可运行的G时会申请创立新的M。比方M在运行G1时被阻塞住了,此时须要新的M去绑定P,如果没有在休眠的M则须要新建M。 面试官:你能给我说说当M0将G1执行完结后会怎么做吗?考点:G在GMP模型中流动过程超超:那我给你举个例子吧(:这次把整个过程都说完,看你还能问什么(图转自刘丹冰Golang的协程调度器原理及GMP设计思维) 调用 go func()创立一个goroutine;新创建的G优先保留在P的本地队列中,如果P的本地队列曾经满了就会保留在全局的队列中;M须要在P的本地队列弹出一个可执行的G,如果P的本地队列为空,则先会去全局队列中获取G,如果全局队列也为空则去其余P中偷取G放到本人的P中G将相干参数传输给M,为M执行G做筹备当M执行某一个G时候如果产生了零碎调用产生导致M会阻塞,如果以后P队列中有一些G,runtime会将线程M和P拆散,而后再获取闲暇的线程或创立一个新的内核级的线程来服务于这个P,阻塞调用实现后G被销毁将值返回;销毁G,将执行后果返回当M零碎调用完结时候,这个M会尝试获取一个闲暇的P执行,如果获取不到P,那么这个线程M变成休眠状态, 退出到闲暇线程中。GM与GMP面试官:看来你对GMP整个流程还是比较清楚的,那你再给我说说GMP绝对于GM做了哪些优化吧。考点:GM与GMP区别超超:优化点有三个,一是每个 P 有本人的本地队列,而不是所有的G操作都要通过全局的G队列,这样锁的竞争会少的多的多。而 GM 模型的性能开销大头就是锁竞争。二是P的本地队列均衡上,在 GMP 模型中也实现了 Work Stealing 算法,如果 P 的本地队列为空,则会从全局队列或其余 P 的本地队列中窃取可运行的 G 来运行(通常是偷一半),缩小空转,进步了资源利用率。三是hand off机制当M0线程因为G1进行零碎调用阻塞时,线程开释绑定的P,把P转移给其余闲暇的线程M1执行,同样也是进步了资源利用率。 面试官:你有没有想过队列和线程的优化能够做在G层和M层,为什么要加一个P层呢?考点:深挖GMP超超:这是因为M层是放在内核的,咱们无权批改,在后面协程的问题中答复过,内核级也是用户级线程倒退成熟才退出内核中。所以在M无奈批改的状况下,所有的批改只能放在用户层。将队列和M绑定,因为hand off机制M会始终扩增,因而队列也须要始终扩增,那么为了使Work Stealing 可能失常进行,队列治理将会变的简单。因而设定了P层作为中间层,进行队列治理,管制GMP数量(最大个数为P的数量)。 面试官:你对GMP还是蛮理解的哈,那回到刚开始的话题,你晓得mac中的回收站只能单开,访达窗口能够多开吧? 超超:晓得呀,这是单例模式(:为什么mac这个点过不去了 未完待续~ 如果你有什么问题想问超超,欢送增加我的微信,进读者群和超超一起探讨呀!

February 26, 2022 · 1 min · jiezi

关于golang:golangleetcode中级x的平方根两数相除分数到小数

第一题 x的平方根题目 二分查找对于算术平方根的计算,咱们能够应用二分查找一直放大边界,最终找到其算术平方根 具体代码func mySqrt(x int) int { l, r := 0, x ans := -1 for l <= r { mid := (r + l) / 2 if mid * mid <= x { ans = mid l = mid + 1 } else { r = mid - 1 } } return ans}成果如下 牛顿迭代法 代码 func mySqrt(x int) int { if x == 0 { return 0 } C, x0 := float64(x), float64(x) for { xi := 0.5 * (x0 + C/x0) if math.Abs(x0 - xi) < 1e-7 { break } x0 = xi } return int(x0)}复杂度剖析 ...

February 25, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表142环形链表-II

力扣链接:https://leetcode-cn.com/probl...解题思路: 题干:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。这道题其实是个数学证明题,过后记得18年找工作面试百度的时候遇到过,这里做一个思路的记录要找到环形列表的入口首先通过寻找链表的环,找到快慢指针的相遇点而后从相遇点作为一个指针,链表结尾做一个指针,同时开始遍历,当他们两个相遇时,就是环的入口/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */// 首先判断链表是否有环// 定义两个指针,快指针每次走两步,慢指针每次走一步,相遇就阐明链表有环// 记录相遇的地位,从新定义两个指针,一个指向头指针,一个指向之前相遇的地位// 同时遍历,相遇的地位就是环的入口func detectCycle(head *ListNode) *ListNode { fast, slow := head, head for fast != nil && fast.Next != nil { // 以后节点不为空,以后节点的下一节点不为空 fast = fast.Next.Next slow = slow.Next if fast == slow { // 找到相遇的节点,阐明有环 circleStart := fast listStart := head for (circleStart != listStart) { circleStart = circleStart.Next listStart = listStart.Next } return circleStart // 相遇时就是入口 } } return nil}

February 25, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表面试题-0207链表相交

力扣链接:https://leetcode-cn.com/probl...解题思路: 首先还是之前的论断,在拿到题目的时候,要先找寻法则,从题干中找出有用的信息,这道题题干中请你找出并返回两个单链表相交的起始节点,这里阐明如果有相交的节点,那么在这个节点之后两个链表是完全相同的,也就是说,从某个节点开始,绝对较短的节点跟绝对较长的节点是末端对齐的如果没有相交的节点,那就返回nil所以这道题的解法就是:先将两个链表的末端对齐,对齐的方法就是较长的链表先走两个链表的差值步,而后两个链表同时开始走,查找是否有雷同的节点,晓得找到/完结双指针:快指针指向较长的链表对齐后的节点,慢指针是较短链表的终点/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */// 实质上还是快慢指针的思维// 先把两个链表尾部对齐// 而后同时开始遍历func getIntersectionNode(headA, headB *ListNode) *ListNode { curA, curB := headA, headB lenA, lenB := 0, 0 // 求链表A的长度 for curA != nil { curA = curA.Next lenA++ } // 求链表B的长度 for curB != nil { curB = curB.Next lenB++ } // 求A和B的差值 diffLen := diffLen(lenA, lenB) var fast, slow *ListNode // 长度更长的先走difflen步 if lenA > lenB { fast = headA slow = headB } else { fast = headB slow = headA } for i := 0; i < diffLen; i++ { fast = fast.Next } // 同时开始走 for fast != slow { fast = fast.Next slow = slow.Next } return fast}func diffLen(a, b int) int { if a > b { return a - b } return b - a}

February 25, 2022 · 1 min · jiezi

关于golang:golangleetcode中级Excel表列序号Powerxn

第一题 Excel表列序号题目 思路列名称对应序列号别离从‘A’到‘Z’对应1到26接着在后面加A,持续从实现从‘A’到‘Z’ 显然,这种进位制的计数法本质上是26进制只不过,因为第一个元素A代表1,这是个没有零的26进制 代码func titleToNumber(columnTitle string) (number int) { for i, multiple := len(columnTitle)-1, 1; i >= 0; i-- { //从字符串最初一个字符开始计算,每个字符乘以26为底它循环次数为幂的倍数失去它代表的理论数值 k := columnTitle[i] - 'A' + 1 number += int(k) * multiple multiple *= 26 } return}也能够由返回后计算 func titleToNumber(columnTitle string) (number int) { ans := 0 for i := 0; i < len(columnTitle); i++{ ans = ans*26+int(columnTitle[i]-'A'+1) } return ans}成果 复杂度剖析工夫复杂度:O(n),其中 n 是列名称 columnTitle 的长度。须要遍历列名称一次。 空间复杂度:O(1)。 ...

February 25, 2022 · 2 min · jiezi

关于golang:Go-核心团队-Russ-Cox-驳斥AWS-博文作者-对-Go-存在严重误导

2 月 23 日,Go 语言外围开发团队 Russ Cox (rsc) 在社交媒体上连发多条推文,“叱责” AWS 官网于前几日公布的一篇博文对 Go 存在着重大的误导。 据悉,AWS 官网博客于 2月 11日 公布了一篇题为《Sustainability with Rust》的文章,该博文作者为 AWS 的 Rust 倡导者兼软件工程师 Shane Miller 和 AWS 首席工程师 Shane Miller。他们在文中对 Rust 语言在 AWS 外部倒退历程以及基于 Rust 推出的一系列 AWS 产品做了回顾,并对该语言的亮点劣势进行了剖析和评估。 这篇博文自身剖析的思路并没什么问题,但作者 Shane Miller 在文中作比拟时,为了突出 Rust 的高效平安,称 Go 语言“是一种垃圾回收(GC)语言,在创立和开释对象时,垃圾收集器须要进行程序的执行并运行垃圾收集过程。”。 听到这样的评估,作为 Go 语言开发团队的 Leader, Russ Cox 天然有些坐不住了,因而要进去对该“误导”舆论进行批驳。 在 AWS 这篇博文中,作者称 Rust 是一种能将 C 等零碎编程语言的性能和资源效率与 Java 等语言的内存平安联合起来的一种语言,是一种“专为开源我的项目而生”的语言。并走漏“ Rust 将很快成为 AWS 大规模建设基础设施倒退的要害”,且 AWS 正在投资 Rust 的可持续性,或将应用这种语言来构建可继续和平安的解决方案。 ...

February 25, 2022 · 2 min · jiezi

关于golang:Leetcode专题链表19删除链表的倒数第-N-个结点

力扣链接:https://leetcode-cn.com/probl...解题思路: 申明虚构头节点,简化链表操作,使得所有的节点操作统一删除倒数第N个节点,能够应用快慢指针,快指针先走,慢指针再走,这样快指针到链表最初一个蒜素的时候,能够应用慢指针删除倒数第N个节点这里须要留神,快指针先走N+1步,使得慢指针正好停在待删除的元素前一个元素,不便删除func removeNthFromEnd(head *ListNode, n int) *ListNode { dummyHead := &ListNode{} slow, fast := dummyHead, dummyHead dummyHead.Next = head for n >=0 && fast != nil { // 多走一步,正好使得slow指针停在待删除的指针上一个地位 fast = fast.Next n-- } for fast != nil { fast = fast.Next slow = slow.Next } slow.Next = slow.Next.Next return dummyHead.Next}

February 25, 2022 · 1 min · jiezi

关于golang:六年老员工的幸福感

刘业兴在 ONES 开办晚期就退出了公司。每当有人问他:「你在 ONES 工作了快6年了,对公司倒退的信念是怎么的?」 他只有一个答复:「素来没有狐疑过。」 以下是刘业兴与 ONES 的故事。 惊喜感和新鲜感我是2016年3月份退出 ONES 的,过后公司一共是十来个人。 此前我的工作经验不算多,相比上一家公司,我到了 ONES 还是感觉蛮有惊喜的。感觉 ONES 的老板很有急躁,创始人会跟咱们讲述他对不同企业的认识,以及 ONES 的倒退方向。 CTO 和研发的共事们都很乐意分享。尽管过后公司的人不多,但咱们会谋求行业内前沿的技术,都心愿把事件能做到极致。我始终感觉 ONES 是特地关注技术提高的公司。 还有,公司给员工的福利待遇、关心,让人感觉是能够跟 ONES 放弃久远的关系。 比如说,创始人认为苹果电脑是最适宜咱们做研发的,于是给咱们的硬件配置都是苹果笔记本电脑;软件方面,老板也会介绍国外优良的软件工具,激励咱们体验和试用,尤其是过后谷歌推出的一些实用的工具。 反正,我在 ONES 的很长时间里都能取得新鲜感。因为我此前用的技术栈并不是支流,也不够先进。而来到 ONES 之后,就会感觉很多货色都是新的,咱们会采纳市面上刚进去的或者行业里比拟认可的新进技术。 具体地说,咱们过后做后端采纳的 Go 语言,就是过后刚进去的,很多公司都还没接触到。但咱们在选型时,判断 Go 语言实用于咱们的分布式架构以及日后的云原生,于是就动摇地采纳了这种语言。 我记得,在那个时候,后端风行的语言还是 Java 。CTO 给咱们解释了 Go 语言的益处、为什么要采纳 Go 语言,以及行业里的状况是怎么的。真的,他的确把咱们都压服了。 咱们研发人员也是能感触到的。依照 CTO 敲定的技术方向,咱们做起来并不辣手,也不难用,往往是在应用的过程中感觉不错的。所以,咱们都不会抗拒既定的技术大方向。 我刚来 ONES 的时候是做挪动端的,当初是做后端,其实是追随公司业务调整而转变过去的。 之所以一开始是做挪动端,是因为公司已经想尝试 ToC 的业务。起初公司调整了策略方向,聚焦做 ToB 业务,我就转到做后端了。 ONES 始终保持做 SaaS 的方向是没变过的,只是起初还有一次大的策略调整,就是阶段性地主打大客户(KA)。再起初就是几轮融资了。 更多的施展空间我在 ONES 快6年了,跟 ONES 一起成长,回过头看,正是因为几次重要的正确策略调整,才减速了公司的增长和倒退,也推动公司有更光明的前景。 ...

February 25, 2022 · 1 min · jiezi

关于golang:第二十九期腾讯微保后台开发面经

一面(局部)聊实习: 聊我的项目: 为什么学Go理解内存透露吗?有什么危害?一道很简略的Go题目,Go怎么做深拷贝。Map是线程平安的吗?怎么解决并发平安问题?sync.Map 怎么解决线程平安问题?看过源码吗?copy是操作符还是内置函数slice的底层原理map的底层原理假如须要启动MongoDB,在linux下怎么设置只能启动一个?当初对什么感兴趣?Go外面一个协程能保障绑定在一个内核线程下面的。本人搭过数据库之类的吗,比方Mongo,MySQL。defer的执行程序defer A ; defer B ; defer panic("") A和B能不能执行到怎么在10万个数中找最大的10个数 没有手撕没有反诘 二面(局部)聊了一点我的项目:Go切片和数据之间的区别切片怎么扩容扩容过程中需不需要从新写入线程和过程怎么看Go的协程能够不能够本人让出cpuGo的协程能够只挂在一个线程下面吗一个协程挂起换入另外一个协程是什么过程?分页和分段内存治理有什么区别内存透露和内存溢出的区别如果一个数组,由10个数,当初只剩8个数,找出剩下的俩个数?这10个数是有某种程序或者法则吗? 没有。。。。。 那不会 那就有法则把,比方1-10. 假如这个世界是重男轻女,生了女孩后肯定会再生,生了男孩后就停,从概率论的角度剖析一下未来这个世界是男多还是女多你怎么对待世界新冠疫情?你感觉新冠疫情期间,西医表演了什么样的作用?emmm................我佛了三面实习和我的项目相干为什么学GoGo和C++有什么区别?想过将来的工作嘛?理解保险嘛?不理解。。。。。MongoDB怎么做备份?MongoDB怎么解决写入失败问题?有动向城市嘛?能够先来实习嘛?什么时候? 谈判一些对实习公司以及微保业务方面的理解 HR面惯例HR问题

February 25, 2022 · 1 min · jiezi

关于golang:golangleetcode中级快乐数阶乘后的零

第一题 高兴数题目 解题思路首先咱们天然须要一个计算高兴数的函数 每一次计算高兴数都是将该数替换为每个地位数字的平方和 var s func(int)int s = func(n int)int{ sum:=0 for n>=10{ i:=n%10 sum+=i*i n=n/10 } sum+=n*n return sum }这样咱们只有调用函数 n=s(n)就实现了一次高兴数的计算 另外高兴数的计算可能是有限循环 为了避免程序进入计算高兴数的死循环退出哈希表存储曾经计算过的数字如果计算出的高兴数已存在于哈希表则阐明进入了循环返回失败 如果计算出高兴数为1则该数为高兴数返回正确 具体代码func isHappy(n int) bool { var s func(int)int s = func(n int)int{ sum:=0 for n>=10{ i:=n%10 sum+=i*i n=n/10 } sum+=n*n return sum } m:=make(map[int]bool) m[n]=true for n!=1{ n=s(n) if m[n]{ return false } m[n]=true } return true}成果 官网解答更简洁的代码func isHappy(n int) bool { m := map[int]bool{} for ; n != 1 && !m[n]; n, m[n] = step(n), true { } return n == 1}func step(n int) int { sum := 0 for n > 0 { sum += (n%10) * (n%10) n = n/10 } return sum}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/happy-number/solution/kuai-le-shu-by-leetcode-solution/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。另外补充对于题目的剖析补充 ...

February 24, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表24两两交换链表中的节点

力扣链接:https://leetcode-cn.com/probl... 新建一个虚构节点,指向head本题没什么非凡的算法,就是模仿模仿分为三个步骤:(0)保留以后节点的下一个节点和第三个节点,因为第二个节点会间接更改,然而这两个须要保留下(1)虚构头节点指向转换前头节点的下一个节点(2)转后节点的下一个节点等于记录的以后节点的下一个节点 (3)第三个节点为之前记录的第三个节点/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */// 模拟法func swapPairs(head *ListNode) *ListNode { dummyHead := &ListNode{} dummyHead.Next = head cur := dummyHead for cur.Next != nil && cur.Next.Next != nil { tmp := cur.Next tmp1 := cur.Next.Next.Next cur.Next = cur.Next.Next cur.Next.Next = tmp cur.Next.Next.Next = tmp1 cur = cur.Next.Next } return dummyHead.Next}

February 24, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表206反转链表

力扣链接:https://leetcode-cn.com/probl...解题思路: 链表题目在做的时候,应用一个虚构头节点是罕用的做法,尤其是须要返回新的头节点时这道题的不同点在于,只是返回翻转的节点,所以头节点肯定是之前的最初一个节点,然而翻转之前的节点须要指向空,所以新建一个空的新节点本题的解法为双指针法:建设两个节点:pre和curtype ListNode Struct { val int next *ListNode}func reverseList(head *ListNode) *ListNode { pre := &ListNode{} cur := head for cur != nil { next := cur.Next cur.Next = pre pre = cur cur = next } return pre}

February 24, 2022 · 1 min · jiezi

关于golang:Leetcode专题链表203移除链表元素

力扣链接:https://leetcode-cn.com/probl...解题思路: 本题要求删除链表中值为val的节点,咱们在解决链表问题的时候,因为头节点比拟非凡,与其余节点的解决形式不同,为了放弃所有节点的解决形式雷同,咱们应用一个虚构节点作为头节点,指向链表的真正头节点,最初返回的时候返回虚构节点的下一个节点即可type ListNode struct { val int next *ListNode}func removeElements(head *ListNode, val int) *ListNode { // 判断以后和以后的下一位是否为空 dummyHead := &ListNode{} dummyHead.Next = head cur := dummyHead for cur != nil && cur.Next != nil { if cur.Next.Val == val { cur.Next = cur.Next.Next } cur = cur.Next } return dummyHead.Next}

February 24, 2022 · 1 min · jiezi

关于golang:第二十七期字节北京抖音后端实习123面经

第一面tcp三次握手udp和tcp区别网络分层IP属于哪一层dsn解释一下过程和线程区别什么是协程协程绝对线程的益处有了过程为什么须要线程线程的共享资源过程之间的通信形式晓得那一些锁介绍一下虚拟内存和益处讲一下分段和分页算法题:负数 0 正数组成的有序数列里找最初一个正数和第一个负数第二面url渲染过程tcp三次握手tcp四次挥手拥塞问题以及如何解决堆和栈的内存调配数组和链表讲一下hashmap的底层实现java怎么解决hashmap的并发问题线程的不同状态和状态之间的切换理解io零碎嘛(不理解)算法题:二叉树的右视图 (下面是当初能想起来的了,之后想起来会加)第三面leader面的,看着就很强 问我了不理解redis的底层实现(我不晓得这个)而后面试官相当于带着我推,推的过程中重要讲的是skiplist以及skiplist的modification等等。 算法题问的是LRU的缓存机制。 三面完结过了几天hr面确定给offer了….

February 24, 2022 · 1 min · jiezi

关于golang:goutildump-打印漂亮易读的go数据

gookit/goutil/dump - 是一个golang数据打印工具包,能够打印出丑陋易读的go slice, map, struct数据。 次要性能: 应用简略,间接调用 dump.P(vars...) 即可反对所有的根底数据类型反对slice, map, struct数据结构反对传入打印多个变量默认输入调用地位,方便使用反对自定义局部能力,如 缩进,色调主题等成果预览: Git Repo:Gitee: https://gitee.com/gookit/goutilGithub: https://github.com/gookit/goutil/GoDoc: https://pkg.go.dev/github.com/gookit/goutil/dump打印根底类型package mainimport "github.com/gookit/goutil/dump"// rum demo:// go run ./dump/_examples/basic_types.gofunc main() { dump.P( nil, true, 12, int8(12), int16(12), int32(12), int64(12), uint(22), uint8(22), uint16(22), uint32(22), uint64(22), float32(23.78), float64(56.45), 'c', byte('d'), "string", )}输入成果: 打印slice打印 array, slice 都会一行一个元素输入,同时会在最初输入长度。 package mainimport "github.com/gookit/goutil/dump"// rum demo:// go run ./dump/_examples/slice.gofunc main() { dump.P( []byte("abc"), []int{1, 2, 3}, []string{"ab", "cd"}, []interface{}{ "ab", 234, []int{1, 3}, []string{"ab", "cd"}, }, )}输入成果: ...

February 23, 2022 · 2 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索搜索二维矩阵-II

题目:编写一个高效的算法来搜寻 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具备以下个性: 每行的元素从左到右升序排列。每列的元素从上到下升序排列。链接: 力扣Leetcode—中级算法—排序和搜寻—搜寻二维矩阵 II. 示例 1: 输出:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5输入:true示例 2: 输出:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20输入:false标签:数组、二分查找、分治、矩阵 思路:从矩阵左下角开始查找,因为矩阵有 每行的元素从左到右升序排列 和 每列的元素从上到下升序排列 的个性。如果以后地位小于target,往右挪动,如果以后大于target,往上挪动,直到找到题目须要的target。 全副Go代码如下: package mainimport "fmt"func searchMatrix(matrix [][]int, target int) bool { // m 行 m := len(matrix) if m == 0 { return false } // n 列 n := len(matrix[0]) if n == 0 { return false } //从左下角开始遍历 i := m - 1 j := 0 for i >= 0 && j < n { // 等于target就输入 if matrix[i][j] == target { return true } else if matrix[i][j] < target { // 如果小于target,列+1 j++ } else { // 剩下大于target状况,行-1 i-- } } return false}func main() { a := [][]int{{1, 4, 7, 11, 15}, {2, 5, 8, 12, 19}, {3, 6, 9, 16, 22}, {10, 13, 14, 17, 24}, {18, 21, 23, 26, 30}} fmt.Println(searchMatrix(a, 5))}提交截图: ...

February 23, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索搜索旋转排序数组遍历二分法

题目:整数数组 nums 按升序排列,数组中的值 互不雷同 。 在传递给函数之前,nums 在事后未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。 给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。 链接: 力扣Leetcode—中级算法—排序和搜寻—搜寻旋转排序数组. 示例 1: 输出:nums = [4,5,6,7,0,1,2], target = 0输入:4示例 2: 输出:nums = [4,5,6,7,0,1,2], target = 3输入:-1示例 3: 输出:nums = [1], target = 0输入:-1标签:数组、二分查找 进阶:你能够设计一个工夫复杂度为 O(log n) 的解决方案吗? ...

February 23, 2022 · 2 min · jiezi

关于golang:golangleetcode中级零钱兑换最长上升子序列

第一题 零钱兑换题目 贪婪(有效)在日常的生存中 ,如果咱们要进行零钱兑换,最奢侈的思维天然是 如果能够应用更大面值的硬币,就优先选择它 这也正是贪婪算法的思维 代码 func coinChange(coins []int, amount int) int { var res int sort.Ints(coins) if amount==0{return 0} for amount>=coins[0]{ index:=sort.SearchInts(coins,amount) if index==len(coins){ amount-=coins[len(coins)-1] res++ continue } if coins[index]!=amount { amount-=coins[index-1] }else{ amount-=coins[index] } res++ } if amount!=0 {return -1} return res}该解法能够通过测试案例 但无奈提交通过 起因是因为 题目提供的硬币组合不肯定是日常中应用的硬币组合 大面值的硬币不肯定是部分最优解 局部能够应用小面值组合组成的数字无奈应用大面值示意 如果想要持续应用贪婪算法,则须要退出回溯语句,排除应用大面值解的计划,再持续搜寻 因为效率过低,在此不持续进行优化 后续优化思路可参考精选题解 https://leetcode-cn.com/probl... 动静布局咱们能够发现 寻找硬币组合的过程 实质上能够拆解成为一个一个筛选硬币的后果 例如: 示例 1:输出:coins = [1, 2, 5], amount = 11输入:3 解释:11 = 5 + 5 + 1 ...

February 22, 2022 · 3 min · jiezi

关于golang:Leetcode专题数组40组合总和II

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题跟39-组合总和https://segmentfault.com/a/11...有相似之处,然而不同点导致这道题的难道实际上是更大的,上面一一剖析首先跟39题相似之处在于,这道题也是回溯法的经典案例,应用的解法雷同不同之处在于:(1)这道题规定数组中的所有数字只能应用一次,那么在进行回溯的时候,start的下标每次要从可选列表的i+1算起 (2)这道题中有反复的数字,然而反复数字也是仅仅只能够应用一次 (3)组合之间不能反复,这个是这道题的重点,在剪枝的时候,组合不能反复,还原成树形构造的时候,其实是每层之间不反复,然而树枝上能够反复,这里独自应用一个数组记录对应的下标是否被应用,依据https://programmercarl.com/00...题解的剖析,当nums[i] == nums[i - 1] && used[i-1]=0时,表明这个数被上一个组合应用过,那么为了防止层之间反复,须要剪掉func combinationSum2(candidates []int, target int) [][]int { res := [][]int{} sort.Ints(candidates) used := make(map[int]bool) backtrack(&res, candidates, []int{}, 0, target, 0, used) return res}func backtrack(res *[][]int, nums, path []int, sum, target, start int, used map[int]bool) { if sum >= target { if sum == target { newPath := make([]int, len(path)) copy(newPath, path) *res = append(*res, newPath) } return } for i := start; i < len(nums); i++ { if i > 0 && nums[i] == nums[i-1] && used[i-1] == false { continue } path = append(path, nums[i]) sum += nums[i] used[i] = true backtrack(res, nums, path, sum, target, i+1, used) path = path[:len(path)-1] sum -= nums[i] used[i] = false }}

February 22, 2022 · 1 min · jiezi

关于golang:Golang开发常见的57个错误

1、不容许左大括号独自一行 2、不容许呈现未应用的变量 3、不容许呈现未应用的import(应用 _ 包名 引入) 4、短的变量申明(Short Variable Declarations)只能在函数外部应用 // myvar := 1 // errorvar myvar = 1 // ok5、不能应用短变量申明(Short Variable Declarations)反复申明 6、不能应用短变量申明(Short Variable Declarations)这种形式来设置字段值 data.result, err := work() //error7、意外的变量幽灵(Accidental Variable Shadowing)代码块中同名短变量申明从申明开始到代码块完结,对变量的批改将不会影响到内部变量! 8、不能应用nil初始化一个未指定类型的变量 9、不能间接应用nil值的Slice和Map 10、map应用make分配内存时可指定capicity,然而不能对map应用cap函数 在golang中,nil只能赋值给指针、channel、func、interface、map或slice类型的变量。 12、数组用于函数传参时是值复制 留神:办法或函数调用时,传入参数都是值复制(跟赋值统一),除非是map、slice、channel、指针类型这些非凡类型是援用传递。 13、range关键字返回是键值对,而不是值 14、Slice和Array是一维的 15、从不存在key的map中取值时,返回的总是”0值” 16、字符串是不可变的 17、字符串与[]byte之间的转换是复制(有内存损耗),能够用map[string] []byte建设字符串与[]byte之间映射,也可range来防止内存调配来进步性能 //[]byte: for i,v := range []byte(str) {}18、string的索引操作返回的是byte(或uint8),如想获取字符可应用for range,也可应用unicode/utf8包和golang.org/x/exp/utf8string包的At()办法。 19、字符串并不总是UTF8的文本 20、len(str)返回的是字符串的字节数 str := "我"fmt.Println(len(str)) //321、在Slice、Array、Map的多行书写最初的逗号不可省略,单行书写,最初一个元素的逗号可省略 22、内置数据结构的操作并不同步,但可把Go提供了并发的个性应用起来:goroutines和channels。 23、应用for range迭代String,是以rune来迭代的。一个字符,也能够有多个rune组成。须要解决字符,尽量应用golang.org/x/text/unicode/norm包。 for range总是尝试将字符串解析成utf8的文本,对于它无奈解析的字节,它会返回oxfffd的rune字符。因而,任何蕴含非utf8的文本,肯定要先将其转换成字符切片([]byte)。 24、应用for range迭代map时每次迭代的程序可能不一样,因为map的迭代是随机的。 25、switch的case默认匹配规定不同于其它语言的是,匹配case条件后默认退出,除非应用fallthrough持续匹配;而其它语言是默认持续匹配,除非应用break退出匹配。 26、只有后置自增(a++)、后置自减,不存在前置自增(++a)、前置自减 27、位运算的非操作是^(跟异或位运算一样),有别于其它语言的~。 28、位运算(与、或、异或、取反)优先级高于四则运算(加、减、乘、除、取余),有别于C语言。 ...

February 22, 2022 · 5 min · jiezi

关于golang:第二十六期腾讯TEG运营开发123HR面经

可能是因为我之前实习和面微信的时候面评都挺不错,所以流程走的很快,问题也不是很难?投的是后盾开发,被经营开发给捞了 1.技术一面 40min1.自我介绍2.我的项目中熔断和限流怎么做的?从源码的角度来说一下3.一致性哈希理解过吗?简略介绍下原理?一致性哈希的利用场景有哪些?为什么比一般哈希好?4.ES搜寻时各个节点怎么工作的?5.对ES的查问做了哪些优化?6.过程线程协程?golang的协程介绍下?7.虚拟内存、物理内存、共享内存介绍下?有什么区别和应用场景?8.让你设计一个过程的数据结构,应该包含哪些数据字段以及别离对应的数据类型,为什么?9.tcp数据包的格局是什么?可选参数有哪些选项?10.tcp拥塞管制介绍下?11.反诘2.技术二面 40min次要都是问之前在腾讯实习的我的项目吧,八股文简直没问。 1.自我介绍2.之前在PCG实习为什么没留用?3.我的项目中熔断怎么做的,介绍一下?4.ES中数据量有多大?查问耗时多少?耗时的瓶颈在哪,怎么去排查的?5.对ES做了哪些查问的优化?6.你这个局部的ES索引是怎么设计的?为什么要这用这种数据类型?7.分词器是用的哪个?为什么要用这个?面完之后面试官间接说等告诉,反诘都没,而且问的不是很难,我还认为是KPI面。 3.技术三面 30min 腾讯三面个别都是部门总监,问的问题个别都是我的项目、架构、设计之类的。 1.自我介绍2.之前实习为什么没留用?3.你怎么对待之前leader对你的评估呢?4.你认为你在PCG实习的这个我的项目中,有哪些亮点和挑战?5.你我的项目中的ES是间接拿来用的吗?(答复:不是)那你介绍下你做了哪些优化和配置的工作?6.用什么语言?(答:golang)golang的协程介绍下?7.介绍下PCG外部的那个...(我怕泄露机密,就不写进去了)8.反诘面试完之后,面试官说HR明天或者今天就会分割我了 4.HR面 30min 腾讯HR小姐姐人都很好,所以HR面挂了的话个别都是业务面排序被刷了 1.自我介绍2.为什么没留用?3.介绍下之前实习的我的项目,以及其中的亮点?4.base在深圳,你能承受吗?5.目前还有哪些其余的offer,会怎么抉择?6.反诘面试最初HR小姐姐说待会就会把云证和测评发过来,果然,面试完10min之后就收到了云证和测评的邮件 。 总体来说腾讯一共面过3次,每次体验都很不错,这次面试一共历经3个工作日,期间我还一度认为被KPI了,最初OC了还是很开心的。

February 22, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组46全排列

力扣链接:https://leetcode-cn.com/probl...解题思路: 回溯算法func permute(nums []int) [][]int { res := [][]int{} backtrack(&res, nums, []int{}) return res}func backtrack(res *[][]int, nums, path []int) { if len(path) == len(nums) { // 切片内存拷贝 newPath := make([]int, len(path)) copy(newPath, path) *res = append(*res, newPath) return } for i := 0; i < len(nums); i++ { if contains(path, nums[i]) { continue } path = append(path, nums[i]) backtrack(res, nums, path) path = path[:len(path) - 1] }}func contains(nums []int, num int) bool { for _, v := range nums { if v == num { return true } } return false}

February 21, 2022 · 1 min · jiezi

关于golang:golangleetcode中级跳跃游戏不同路径

第一题 跳跃游戏题目 贪婪解法对于每个下标而言,元素规定了它能够达到的最大间隔 因而这部分间隔范畴内的下标都是能够到达的. 例如示例1:nums = [2,3,1,1,4]. 对于下标0而言,它能够抉择下标1或者下标2 抉择下标1.能够达到下标4 抉择下标2,能够达到下标3 .因为本题返回值为布尔类型,无需存储跳跃门路 咱们只需记住跳跃能达到的最远下标即可, 对于最远下标以内,咱们总能找到一条能够到达的门路 因而咱们能够失去公式 maxIndex=max(maxIndex,i+nums[i]) 直到最远下标到达最初一个下标 if maxIndex>=n-1 {return true} 核心思想为 贪婪算法 ,即优先思考可取得的最佳的解法 对于每个下标,咱们都将其最优解退出思考范畴 具体代码 func canJump(nums []int) bool { n:=len(nums) var maxIndex int for i:=0;i<n;i++{ if i>maxIndex{return false} maxIndex=max(maxIndex,i+nums[i]) if maxIndex>=n-1 {return true} } return false}func max(x int,y int)int { if x<y{ return y }else { return x }}官解 动静布局解法在用动静布局求解之前,让咱们在强调一下动静布局的几个步骤具体学习能够参考https://labuladong.gitee.io/a... https://houbb.github.io/2020/... 而对于本题而言 代码func canJump(nums []int) bool { n:=len(nums) a:=nums[0] // a=dp[i-1] for i:=1;i<n;i++ { if a==0 {return false} a=max(a-1,nums[i]) // a=dp[i] } return true}func max(x int,y int)int { if x<y{ return y }else { return x }}复杂度剖析工夫复杂度:O(n),其中 n 为数组的大小。只须要拜访 nums 数组一遍,共 n 个地位。 ...

February 21, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组216组合总和-III

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题目的解题思路是回溯算法,回溯算法是有固定的模版套路的,简略来说有以下三个条件:(1)抉择列表,代表门路抉择的时候从哪个列表中抉择数据 (2)门路列表,示意哪些数字曾经被抉择进以后门路 (3)终止条件,示意什么时候完结循环,个别是k个数的时候或者和为target的时候private void backtrack("原始参数") { //终止条件(递归必须要有终止条件) if ("终止条件") { //一些逻辑操作(可有可无,视状况而定) return; } for (int i = "for循环开始的参数"; i < "for循环完结的参数"; i++) { //一些逻辑操作(可有可无,视状况而定) //做出抉择 //递归 backtrack("新的参数"); //一些逻辑操作(可有可无,视状况而定) //撤销抉择 }}伪代码如上所示,在这道题中,有两个完结抉择条件,一个是当门路中的数量等于规定的k个时,另一个是所有的数字和n<=0时;下标从1~9。能够写出代码如下: func combinationSum3(k int, n int) [][]int { res := [][]int{} backtrack(&res, []int{}, k, n , 1) return res}func backtrack(res *[][]int, path []int, k, n, start int) { if len(path) == k || n <= 0 { if len(path) == k && n == 0 { newPath := make([]int, len(path)) copy(newPath, path) *res = append(*res, newPath) } return } for i := start; i <= 9; i++ { path = append(path, i) backtrack(res, path, k, n - i, i + 1) path = path[:len(path) - 1] }}

February 21, 2022 · 1 min · jiezi

关于golang:Go118-新特性高效复制strings-bytes-标准库新增-Clone-API

大家好,我是煎鱼。 Go1.18 过几周(3月份)就要公布了,先前咱们曾经更新了好几期新版本个性,明天给大家带来一个新的优化类的内容,是与 strings 和 bytes 规范库无关。 背景想要更快捷复制在日常编程中,字节 []byte 是常常须要复制的。须要写以下代码: dup := make([]byte, len(data))copy(dup, data)@Ilia Choly 感觉这就太麻烦了,毕竟每次都得写一遍,又或是本人封装成如下函数: // Clone returns a copy of bfunc Clone(b []byte) []byte { b2 := make([]byte, len(b)) copy(b2, b) return b2}为此想要减少一个快捷办法,不过这显然站不住脚,相熟语法的同学会发现有现成的形式: b2 := append([]byte(nil), b...)一行就能实现成果,甚至更快,因为调配的切片不会被初始化为零值。 复制会共享内存许多 Go 开发者,在写应用程序要复制切片(Slice)时,会发现复制进去的切片 s1 和原始的 s0 有内存上的关联,其本质起因在于其底层的数据结构导致,这会导致许多暗藏的问题。 示例代码如下: import ( "fmt" "reflect" "unsafe")func main() { s0 := "脑子进煎鱼了" s1 := s0[:3] s0h := (*reflect.StringHeader)(unsafe.Pointer(&s0)) s1h := (*reflect.StringHeader)(unsafe.Pointer(&s1)) fmt.Printf("Len is equal: %t\n", s0h.Len == s1h.Len) fmt.Printf("Data is equa: %t\n", s0h.Data == s1h.Data)}从上述程序来看,你认为变量 s0 和 s1 相比,他们的 Len 相等吗?Data 相等吗? ...

February 21, 2022 · 2 min · jiezi

关于golang:Leetcode专题数组39组合总和

力扣链接:https://leetcode-cn.com/probl...解题思路: 数组求排列的解题思路,个别都是回溯法+剪枝回溯法是有固定套路的,依照固定套路解题即可回溯法固定套路 (1)定义起始地位,个别是数组的首地位;定义path门路,即选取的元素是哪些,定义总数和(该题目中须要总数和来确定循环完结) (2)确定循环完结条件,本题目中总和大于等于target的时候,循环完结 (3)回溯外围代码,因为数组数字能够反复,然而[2,2,3]和[2,3,2]其实是同一个组合,那么就要保障抉择的时候,不反复path,能够通过for循环来管制,i每次往后选即可func combinationSum(candidates []int, target int) [][]int { res := [][]int{} // 定义后果 var dfs func(start, sum int, path []int) dfs = func(start, sum int, path []int) { if sum >= target { // 循环完结剪枝 if sum == target { newPath := make([]int, len(path)) copy(newPath, path) res = append(res, newPath) } return } for i := start; i < len(candidates); i++ { // i每次加一,不反复选 path = append(path, candidates[i]) dfs(i, sum + candidates[i], path) path = path[:len(path) - 1] } } dfs(0, 0, []int{}) return res}

February 21, 2022 · 1 min · jiezi

关于golang:第二十五期最右社招Golang工程师面经

最右APP 2技术1hr已offer 一面工作我的项目比拟有成就感的产出redis相干,网络模型,存储模型,罕用数据结构等缓存穿透解决方案分布式系统CAP工作我的项目中以及其余共识算法raft算法细节(选主 复制 脑裂balabala)mysql索引相干,数据结构,优化,优缺点等主键须要保障的个性以及为什么这样做二面场景题:某个上游服务的接口并发量大应该如何解决? § 给出了一个复用资源(池)的思路, 诘问:引入池后会呈现哪些问题,如何预防?聊工作我的项目,很多问题基于我的项目问的hr1.聊人生

February 21, 2022 · 1 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索寻找峰值二分法

题目:峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能蕴含多个峰值,在这种状况下,返回 任何一个峰值 所在位置即可。 你能够假如 nums[-1] = nums[n] = -∞ 。 你必须实现 工夫复杂度为 O(log n) 的算法来解决此问题。 链接: 力扣Leetcode—中级算法—排序和搜寻—寻找峰值. 示例 1: 输出:nums = [1,2,3,1]输入:2解释:3 是峰值元素,你的函数应该返回其索引 2。示例 2: 输出:nums = [1,2,1,3,5,6,4]输入:1 或 5 解释:你的函数能够返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。标签:数组、二分查找 思路:本题首先最容易想到的就是遍历数组,找出第一个符合条件的元素就能够了,这很简略,然而不满足O(logN)的工夫复杂度要求 那么咱们想要满足O(logN)的工夫复杂度要求,那么必定就是采纳二分法 二分法: 定义高下两个指针low,high,别离指向数组首位定义两头指针mid=(low+high)/2咱们晓得二分法的完结标记是low>=high,当low==high的时候,算法必定完结而后咱们每次判断两头值,如果两头值处于降落状态,那么能够必定两头值的右边有比两头值大的数,而数组中间又是十分小的数,所以峰值必定在右边,所以咱们二分法的下一次开始就是让high=mid如果两头值处于回升状态,那么峰值必定就在两头值的左边,所以二分法的下一次开始就是让low=mid+1你须要认真感触high=mid和low=mid+1这两个等式,琢磨轻微之处,能够发现low随着mid挪动,而high最多等于mid,认真琢磨他们的区别全副Go代码如下: package mainimport "fmt"//二分法func findPeakElement(nums []int) int { low, high := 0, len(nums)-1 for low < high { mid := (low + high) / 2 if nums[mid] > nums[mid+1] { high = mid } else { low = mid + 1 } } return low}func main() { a := []int{1, 2, 3, 1} fmt.Println(findPeakElement(a))}提交截图: ...

February 21, 2022 · 2 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索数组中的第K个最大元素

题目:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请留神,你须要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 链接: 力扣Leetcode—中级算法—排序和搜寻—数组中的第K个最大元素. 示例 1: 输出: [3,2,1,5,6,4] 和 k = 2输入: 5示例 2: 输出: [3,2,3,1,2,4,5,5,6] 和 k = 4输入: 4标签:数组、分治、疾速抉择、排序、堆(优先队列) 思路:先用 sort.Sort(sort.Reverse(sort.IntSlice(nums))) 对数组进行从大到小排序,再找出数组中第 k 个最大的元素。 全副Go代码如下: package mainimport ( "fmt" "sort")func findKthLargest(nums []int, k int) int { // 数组从大到小排序 sort.Sort(sort.Reverse(sort.IntSlice(nums))) var max int max = nums[k-1] return max}func main() { a := []int{3, 2, 1, 5, 6, 4} fmt.Println(findKthLargest(a, 2))}提交截图: ...

February 21, 2022 · 1 min · jiezi

关于golang:go微服务开发工具箱

序应用golang开发了一阵子业务代码,本文次要梳理一下本人的应用感触,并总结一下罕用的类库,不便查阅。因为自己是java重度使用者,未免加以比照吐槽一下,请见谅。 go做业务开发?比照java这里说说用go做业务开发的感触: 长处 云原生首选,省内存挺适宜写脚本的,可代替python毛病 没应用好会panic,线上服务间接过程退出还挺重大的go没有maven的SNAPSHOT版本,基于commit hash加日期作为伪版本,很容易呈现invalid version,体验十分不好,不像SNAPSHOT这么省事写面向对象比拟吃力,每个办法都要写个receiver,不像java这么规整ioc的反对不像java有ioc的规范,生态也不太行,比方uber/dig,都无奈按name注入map构造godoc太简陋了,没有javadoc那么规整没有注解和泛型(尽管新版反对了,然而要等周边生态反对了能力好好用上),语言表达力弱了很多至于协程,业务开发貌似这个派不上用场包的机制挺怪的,默认以最初一个为准,很容易抵触,也不容易辨识,若是加上别名,那更是劫难,十分不利于剖析不足好用的test suite,不像java的juint,写几个注解就能够,挺吃力的golang常见类库参数校验 go-playground/validator测试加强 testifygomonkeygoconvey类型转换 castgo-convcopier反射 go-reflector序列化 mapstructurejson-iterator数据结构加强 decimalatomicerrorsmultierrgodsgo-datastructuresgolang-setstream操作 go-funkgo-linq依赖注入 didigfx微服务相干 viperhdrhistogram-gohystrix-gosentinel-golangclient_golangopentracing-gojaeger-client-goredislockentroq总结用go进行业务开发感觉老本还挺大,相对不是省内存,云原生这么简略的事件,如果是大公司,能够用钱去砸,我没话说。中小公司如果本身团队不是go背景,想从零开始,感觉老本还挺大,集体愚见。

February 20, 2022 · 1 min · jiezi

关于golang:Go语言map排序keyvalue排序

1、前言Go语言的map是无序的,屡次遍历map的后果可能是不同的,比方: package mainimport ( "fmt")func Map() (result map[int]uint32) { result = map[int]uint32{} // 插入各个数据 result[24] = 240 result[17] = 170 result[9] = 90 result[11] = 110 result[55] = 550 return}func main() { mapResult := Map() // 遍历map for key, value := range mapResult { fmt.Printf("key = %v,value = %v\n", key, value) }}第一次遍历后果如下:第二次遍历后果如下:能够看到两次遍历的后果是不同的 2、实现map遍历有序2.1 key有序思路:对key排序,再遍历key输入value 2.1.1 从小到大排序sort.Sort(sort.IntSlice(keys))代码如下: package mainimport ( "fmt" "sort")func Map() (result map[int]uint32, keys []int) { result = map[int]uint32{} keys = []int{} // 插入各个数据 result[24] = 240 result[17] = 170 result[9] = 90 result[11] = 110 result[55] = 550 // 失去各个key for key := range result { keys = append(keys, key) } // 给key排序,从小到大 sort.Sort(sort.IntSlice(keys)) return}func main() { mapResult, keys := Map() // 遍历map for _, key := range keys { fmt.Printf("key = %v,value = %v\n", key, mapResult[key]) }}后果: ...

February 20, 2022 · 2 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索前K个高频元素哈希表存储

题目:给你一个整数数组 nums 和一个整数 k ,请你返回其中呈现频率前 k 高的元素。你能够按 任意程序 返回答案。 链接: 力扣Leetcode—中级算法—排序和搜寻—前K个高频元素. 示例 1: 输出: nums = [1,1,1,2,2,3], k = 2输入: [1,2]示例 2: 输出: nums = [1], k = 1输入: [1]标签:数组、哈希表、分治、桶排序、计数、疾速抉择、排序、堆(优先队列) 思路:用哈希表来存储次数,再遍历这个哈希表,返回其中呈现频率前 k 高的元素 全副Go代码如下: package mainimport ( "fmt")func topKFrequent(nums []int, k int) []int { // 用一个map来存储数字以及呈现的次数 m := make(map[int]int) for _, v := range nums { m[v]++ } fmt.Println(m) // 定义存储最初后果的数组 var res []int for i := 0; i < k; i++ { res = append(res, 0) f := 0 for n, v := range m { if v > f { res[i] = n f = v } } m[res[i]] = -1 } return res}func main() { a := []int{3, 0, 1, 0} fmt.Println(topKFrequent(a, 1))}提交截图: ...

February 20, 2022 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看函数命名返回值的注意事项超过80的人都回答错了

题目Redhat的首席工程师、Prometheus开源我的项目Maintainer Bartłomiej Płotka 在Twitter上出了一道Go编程题,后果超过80%的人都答复错了。 题目如下所示,答复上面这段程序的输入后果。 // named_return.gopackage mainimport "fmt"func aaa() (done func(), err error) { return func() { print("aaa: done") }, nil}func bbb() (done func(), _ error) { done, err := aaa() return func() { print("bbb: surprise!"); done() }, err}func main() { done, _ := bbb() done()}A: bbb: surprise!B: bbb: surprise!aaa: doneC: 编译报错D: 递归栈溢出大家能够先思考下这段代码的输入后果是什么。 解析在函数bbb最初执行return语句,会对返回值变量done进行赋值, done := func() { print("bbb: surprise!"); done() }留神:闭包func() { print("bbb: surprise!"); done() }里的done并不会被替换成done, err := aaa()里的done的值。 ...

February 20, 2022 · 4 min · jiezi

关于golang:Golang力扣Leetcode中级算法排序和搜索颜色分类指针

题目:给定一个蕴含红色、红色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得雷同色彩的元素相邻,并依照红色、红色、蓝色顺序排列。 咱们应用整数 0、 1 和 2 别离示意红色、红色和蓝色。 必须在不应用库的sort函数的状况下解决这个问题。 链接: 力扣Leetcode—中级算法—排序和搜寻—色彩分类. 示例 1: 输出:nums = [2,0,2,1,1,0]输入:[0,0,1,1,2,2]示例 2: 输出:nums = [2,0,1]输入:[0,1,2]标签:数组、双指针、排序 思路:利用三个指针 left 示意0的右边界,right 示意2的左边界,cur 示意以后遍历的地位。( left <= cur <= right ) 当nums[cur]==0时,与left调换,并且left++ cur++。因为left肯定<=cur,所以换过来的数字必定是0或者1,所以cur++。当nums[cur]==2时,与right调换,并且right--,因为right对应的数字没有扫描过,不确定换回来的数字的大小,因而cur不变,下次循环须要再遍历一次cur处的值。cur<=right而不是小于right,因为right地位的数还没有扫描过全副Go代码如下: package mainimport "fmt"func main() { var nums = []int{2, 0, 2, 1, 1, 0} var n = len(nums) // 以后地位 var cur int // 0 的右边界 var left int // 2 的左边界 var right = n - 1 var tmp int for cur <= right { // 当nums[cur]==0时,与left调换,并且left++ cur++。因为left肯定<=cur,所以换过来的数字必定是0或者1,所以cur++。 if nums[cur] == 0 { tmp = nums[left] nums[left] = nums[cur] nums[cur] = tmp left++ cur++ } else if nums[cur] == 2 { // 当nums[cur]==2时,与right调换,并且right--,因为right对应的数字没有扫描过,不确定换回来的数字的大小,因而cur不变,下次循环须要再遍历一次cur处的值。 tmp = nums[right] nums[right] = nums[cur] nums[cur] = tmp right-- } else { // cur<=right而不是小于right,因为right地位的数还没有扫描过 cur++ } } fmt.Println(nums)}提交截图: ...

February 20, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组36有效的数独

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题的解法是奢侈遍历首先遍历每一行是否有反复其次遍历每一列是否有反复遍历33的格子是否有反复func isValidSudoku(board [][]byte) bool { for i := 0; i < len(board); i++ { for j := 0; j < len(board[i]); j++ { if i % 3 == 0 && j % 3 == 0 && !isValidSquare(board, i, j) { return false } if !isValidXY(board, i, j) { return false } } } return true}func isValidSquare(board [][]byte, x, y int) bool { m := map[byte]bool{} for i := x; i < x + 3; i++ { for j := y; j < y + 3; j++ { if board[i][j] == '.' { continue } if m[board[i][j]] { return false } m[board[i][j]] = true } } return true}func isValidXY(board [][]byte, x, y int) bool { mx := make(map[byte]bool) for i := 0; i < 9; i++ { if board[x][i] == '.' { continue } if mx[board[x][i]] { return false } mx[board[x][i]] = true } my := make(map[byte]bool) for j := 0; j < 9; j++ { if board[j][y] == '.' { continue } if my[board[j][y]] { return false } my[board[j][y]] = true } return true}

February 20, 2022 · 1 min · jiezi

关于golang:golangleetcode中级搜索旋转排序数组搜索二维矩阵Ⅱ

第一题 搜寻旋转排序数组题目 解题思路 代码func search(nums []int, target int) int { //初始化边界和二分搜寻的中点 l := 0 r := len(nums) - 1 var mid int for l <= r{ //取中点,如果中点为指标则间接返回 mid = l + (r - l) / 2 if target == nums[mid]{ return mid } //mid至多会有一端有序,能够利用有序段膨胀边界。 if nums[mid] >= nums[l] {//左端有序 if target < nums[mid] && target >= nums[l] { //元素在左端 r = mid - 1 }else{ //排除左端 l = mid + 1 } }else{//右端有序 if target > nums[mid] && target <= nums[r] { //元素在右端 l = mid + 1 }else{ //排除右端 r = mid - 1 } } } return -1}复杂度剖析工夫复杂度: O(logn),其中 n 为 nums 数组的大小。整个算法工夫复杂度即为二分查找的工夫复杂度 O(logn)。 ...

February 20, 2022 · 2 min · jiezi

关于golang:golangleetcode中级在排序数组中查找元素的第一个和最后一个位置合并区间

第一题 在排序数组中查找元素的第一个和最初一个地位题目 谬误案例func searchRange(nums []int, target int) []int { res:=make([]int,2) n:=len(nums) if n==1{ if nums[0]==target{ return res }else{ res[0]=-1 res[1]=-1 return res } } mid:=n/2 s1:=searchRange(nums[:mid],target) s2:=searchRange(nums[mid:], target) if s1[0]==-1&&s2[0]==-1{ res[0]=-1 res[1]=-1 return res } if s1[0]==-1{ res[0]=s2[0]+mid res[1]=s2[1]+mid }else if s2[0]==-1{ res[0]=s1[0] res[1]=s1[1] }else{ res[0]=s1[0] res[1]=s2[1]+mid } return res}后果 .... 起因是因为 正确解法 func searchRange(nums []int, target int) []int { leftmost := sort.SearchInts(nums, target) if leftmost == len(nums) || nums[leftmost] != target { return []int{-1, -1} } rightmost := sort.SearchInts(nums, target + 1) - 1 return []int{leftmost, rightmost}}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。解析 ...

February 19, 2022 · 1 min · jiezi

关于golang:时间轮与gozero中时间轮的实现解析

工夫轮用于提早工作的调度。 场景设想这么一个场景,我须要保护一个连接池,连接池中的连贯是有超时工夫的,连贯会放弃肯定频率发送心跳包比方5s发一次,30s内如果没有收到keep-alive就会过期,到过期工夫的conn断开连接,如何去设计这个连接池? 场景形象这个场景能够了解为,我收到一个申请之后,在提早30秒后须要执行一个动作,并且如果在30s内收到同样的申请,就把这个工作再推延30s,咱们应该怎么做呢? 可行解那假如我的连接池最大连接数是1000,简略的办法是每个连贯保护一个最近的keep-alive工夫,启动一个定时器,每秒去遍历一次所有连贯,到工夫了就断开连接。收到心跳时,更新这个连贯的工夫,那如果有10000个连贯呢?每秒就要遍历10000次能力确定哪些工作要删掉,这种形式是很浪费资源的。 更优解应用工夫轮算法,工夫轮算法的根本思维是将提早工作扩散,不在一个中央去保护,防止因为都放在一个中央,每次都要进行遍历的损失。怎么把工作进行扩散呢?依照提早工作的最大工夫限度和timer执行的工夫,比方说我最大反对提早60秒,每秒都扫一次,那我就能够建设一个数组叫做timeWheel,timeWheel上放的是这个工夫到期的连贯组成的数组connList,保护一个cur_index,指向timeWheel的某一个index。执行的流程是从这个index开始向后遍历,每秒挪动一个index,到最大index的时候返回到0持续循环,每次挪动都断开index外面所有连贯。接管到心跳时,把这个连贯从以后的timeWheel的index中去掉,index减少30后对60取模保障不越界。 优化:尽管每秒做删除的时候不必扫数组了,然而这样的话,收到心跳的时候就要扫数组了,那怎么优化收到心跳时扫数组的操作呢?从timeWheel取连贯的过程能够通过map做conn到timeWheel中index的索引,不用查找整个工夫轮。在conn批改timeWheel的index, 图解 缺点这个场景中,最大延迟时间是60s,所以一个大小为60的timeWheel就够了,那如果是一天呢?一天是86400s,就须要用到86400大小的timeWheel了。能够通过分层来做优化。 多层工夫轮多层工夫轮是单层工夫轮的优化计划,用于缓解单层工夫轮在工夫范畴大,跨度小的状况下,timeWheel的大小也须要增大的状况。 场景把下面的场景的工夫范畴裁减到7天,86400s*7 怎么分层对于这种场景,咱们能够分为4层工夫轮。第一层timeWheel1示意秒,大小为60,每个元素示意1s。第二层timeWheel2示意分,大小为60,每个元素示意1m。第三层timeWheel3示意小时,大小为24,每个元素示意1h。第四层timeWheel4示意天,大小为7,每个元素示意1d。 执行流程前提设定假如以后timeWheel的状态如下timeWheel1的60个index都为空,cur_index1在index0地位timeWheel2的60个index都为空,cur_index2在index0地位timeWheel3的24个index都为空,cur_index3在index0地位timeWheel4的7歌index都为空,cur_index4在index0地位 工作增加流程接管到一个工作1,须要提早7100s之后执行,计算是否能够落到timeWheel1中。7100比timeWheel1的最大范畴60大,不能放在timeWheel1中。计算是否能够落到timeWheel2中。7100/60 = 118.333向下取整118,118比timeWheel2的最大范畴60大。不能放在timeWheel2中。计算是否能够落到timeWheel3中。$7100/(60*60) = 1.97222$,1.97222向下取整得1,1比timeWheel3的最大范畴24小,能够放在timeWheel3中。计算下一级残余多少工夫:$7100 % (60*60) = 3500$,还剩下3500s,存储在cur_index3+1这个地位上,同时保留残余的工夫3500。这也就是工夫轮的降级过程。 工夫轮运行流程运行的时候波及到工夫轮的降级过程。以四层环为例一个简略暴力的实现思路是,提前定义有多少层环,有多少层环,就开多少个定时器。下层定时器到工夫,把对应cur_index中的工作放到上层定时器中,这种须要进行这几个环的一个解决程序做同步,不然可能呈现下层放到上层的时候,上层曾经走过了这个地位的状况。 另一个实现形式是只有一个定时器,先走最底层,最底层走完一圈的时候走下层,通过下层这个cur_index中的工作的剩余时间来判断,没有剩余时间的立刻执行,有剩余时间的放到底层的。如果这一层也跑了一圈,再去上一层取工作。以此类推,实现较为简单。 go-zero中的实现是2层循环,能够保护了一个底层slot和一个循环圈数circle,每次扫描的数量尽管多了,然而实现简略,能够在上面的源码中参考一下。 工夫轮在go中的实现Go语言中工夫轮的实现齐全兼容golang定时器的高性能工夫轮实现(go-timewheel)go-zero中工夫轮的实现 go-zero中工夫轮源码正文go-zero中的timeWheel用于程序外部缓存cache的过期清理操作。以下只关怀工夫轮的实现形式。 // 工夫轮构造体type TimingWheel struct { interval time.Duration //工夫轮每个槽位的工夫距离 ticker timex.Ticker //定时器 slots []*list.List //槽位数组 timers *SafeMap //一个避免内存透露的map,用来装什么的? tickedPos int //当初指向的槽位 numSlots int //槽数 execute Execute //到工夫执行的函数 // 对外提供的办法,通过channel来与timeWheel交互 // 这种交互方式的益处大略是对于不关怀后果的调用方起到解耦成果,不须要同步期待 setChannel chan timingEntry //设置接口 moveChannel chan baseEntry //挪动接口 removeChannel chan interface{} //删除接口 drainChannel chan func(key, value interface{}) // stopChannel chan lang.PlaceholderType //完结接口}//工夫轮元素构造体type timingEntry struct { baseEntry value interface{} circle int diff int removed bool}//根底字段type baseEntry struct { delay time.Duration key interface{}}//key到slot的映射,以及一个timingEntry元素指针,//用于通过key在timers中疾速查找到元素type positionEntry struct { pos int item *timingEntry}//提早工作字段type timingTask struct { key interface{} value interface{}}//办法定义//以下办法是对外提供的办法,通过channel发送信号,run办法中监听各个channel,收到信号执行相应的办法//立即执行所有工作func (tw *TimingWheel) Drain(fn func(key, value interface{})) //工作没到工夫就把工作的延迟时间更新。到工夫就间接执行。func (tw *TimingWheel) MoveTimer(key interface{}, delay time.Duration)//移除一个工作func (tw *TimingWheel) RemoveTimer(key interface{})//减少一个工作func (tw *TimingWheel) SetTimer(key, value interface{}, delay time.Duration)//进行工夫轮func (tw *TimingWheel) Stop()//以下办法是真正执行的办法func (tw *TimingWheel) drainAll(fn func(key, value interface{}))//pos用 延迟时间/槽位示意的工夫 先计算出往后数第几个槽,思考溢出和以后的槽位偏移,最终的pos = (tickedPos+d/interval)%numSlots//circle = (d/interval-1)/numSlotsfunc (tw *TimingWheel) getPositionAndCircle(d time.Duration) (pos, circle int)func (tw *TimingWheel) initSlots()func (tw *TimingWheel) moveTask(task baseEntry)func (tw *TimingWheel) onTick()func (tw *TimingWheel) removeTask(key interface{})func (tw *TimingWheel) removeTask(key interface{})func (tw *TimingWheel) run()func (tw *TimingWheel) runTasks(tasks []timingTask)func (tw *TimingWheel) scanAndRunTasks(l *list.List)// func newTimingWheelWithClock(interval time.Duration, numSlots int, execute Execute, ticker timex.Ticker) ( *TimingWheel, error) { tw := &TimingWheel{ interval: interval, ticker: ticker, slots: make([]*list.List, numSlots), timers: NewSafeMap(), tickedPos: numSlots - 1, // at previous virtual circle execute: execute, numSlots: numSlots, setChannel: make(chan timingEntry), moveChannel: make(chan baseEntry), removeChannel: make(chan interface{}), drainChannel: make(chan func(key, value interface{})), stopChannel: make(chan lang.PlaceholderType), } tw.initSlots() go tw.run() return tw, nil}// Drain drains all items and executes them.func (tw *TimingWheel) Drain(fn func(key, value interface{})) { tw.drainChannel <- fn}//run办法,监听所有channel,在newTimeWheel的时候就启动了。func (tw *TimingWheel) run() { for { select { case <-tw.ticker.Chan(): //到工夫,执行对应slot上须要执行的工作。 tw.onTick() case task := <-tw.setChannel: //往工夫轮上增加一个工作 tw.setTask(&task) case key := <-tw.removeChannel: //从工夫轮上删除一个工作 tw.removeTask(key) case task := <-tw.moveChannel: //更新一个工夫轮上工作的执行工夫 tw.moveTask(task) case fn := <-tw.drainChannel: tw.drainAll(fn) case <-tw.stopChannel: tw.ticker.Stop() return } }}//先看减少,也就是setTask办法//调用:// run -> setTask//逻辑:// 从map索引中确定,这个工作是否曾经存在了// 存在的话就通过moveTask挪动这个工作的地位// 不存在的话,就计算出工作在环中绝对于以后的ticked的定位,以及要转的圈数circle,将工作放在环上,并且保护map索引func (tw *TimingWheel) setTask(task *timingEntry) { if task.delay < tw.interval { task.delay = tw.interval } if val, ok := tw.timers.Get(task.key); ok { entry := val.(*positionEntry) entry.item.value = task.value tw.moveTask(task.baseEntry) } else { pos, circle := tw.getPositionAndCircle(task.delay) task.circle = circle tw.slots[pos].PushBack(task) tw.setTimerPosition(pos, task) }}// 减少看完了,再看一下是怎么执行的,假如曾经扫到了这个工作所在的slot,// 先保护一下曾经扫到的地位,而后从slot中拿出对应的list,扔到scanAndRunTask办法中执行。func (tw *TimingWheel) onTick() { tw.tickedPos = (tw.tickedPos + 1) % tw.numSlots l := tw.slots[tw.tickedPos] tw.scanAndRunTasks(l)}// 次要看scanAndRunTask办法,这个办法是真正在拿到list之后做的操作//逻辑:// 遍历整个list,先革除被删掉工作,再将循环圈数不为0的工作的圈数-1,// 剩下的是圈数为0的无效工作,思考到有更新操作,更新操作的pos会推延到真正要执行的时候做,所以还要依据diff再看一下是不是一个被更新的操作。// 最初后面这些都被过滤掉,剩下来的工作就是这次scan要执行的工作,把他们退出到执行队列中,通过runTask办法并发执行,这个办法中会管制并发数。func (tw *TimingWheel) scanAndRunTasks(l *list.List) { var tasks []timingTask for e := l.Front(); e != nil; { task := e.Value.(*timingEntry) if task.removed { next := e.Next() l.Remove(e) e = next continue } else if task.circle > 0 { task.circle-- e = e.Next() continue } else if task.diff > 0 { next := e.Next() l.Remove(e) // (tw.tickedPos+task.diff)%tw.numSlots // cannot be the same value of tw.tickedPos pos := (tw.tickedPos + task.diff) % tw.numSlots tw.slots[pos].PushBack(task) tw.setTimerPosition(pos, task) task.diff = 0 e = next continue } tasks = append(tasks, timingTask{ key: task.key, value: task.value, }) next := e.Next() l.Remove(e) tw.timers.Del(task.key) e = next } tw.runTasks(tasks)}// 更新timeWheel中已存在的工作的延迟时间// 调用:// run -> setTask -> moveTask 在setTask中判断如果有这个key就moveTask// run -> moveTaskfunc (tw *TimingWheel) moveTask(task baseEntry) { val, ok := tw.timers.Get(task.key) if !ok { return } timer := val.(*positionEntry) //如果task设置的延迟时间太小了,那就间接执行 if task.delay < tw.interval { threading.GoSafe(func() { tw.execute(timer.item.key, timer.item.value) }) return } // 没到工夫,须要扭转地位,依据新的延迟时间计算出新的定位和circle pos, circle := tw.getPositionAndCircle(task.delay) //依据pos和circle还有旧数据,批改task的信息,做一些标记,在扫描到这个task的时候再真正批改和从新定位。 //提早这些更改的益处是,如果某些key频繁改变的话,不须要频繁进行重定位操作,重定位操作须要保障并发平安。 if pos >= timer.pos { //新pos大于等于旧pos,更新工作的circle,pos还是用旧的,而是把工作的diff更新为新pos-旧pos,这里是为什么? //思考场景,先触发tick,再触发move,因为tick运行工作的时候是go进来的,go进来的工作正在执行,这时候如果来move申请,就会有并发问题 //这里记录他的diff是标记曾经被改过了,下次跑到这个工作的时候就会触发pos更新。 timer.item.circle = circle timer.item.diff = pos - timer.pos } else if circle > 0 { //pos提前了,不在这一圈触发,得算一下diff偏移量和走多少圈 circle-- //把diff的一圈扣掉 timer.item.circle = circle //算diff把circle扣的一圈加回来 假如新pos是1,旧pos是2,num是5,diff就是4,示意 2+4=6,6%5=1,计算的时候,这里就会计算为1 timer.item.diff = tw.numSlots + pos - timer.pos } else { //pos提前了,并且就是这次循环,删除旧的增加新的 // 这里是不是没有思考到并发的状况?如果正在执行这个工作,那这里会不会有问题? // 如果思考就算执行完,也要生成新的继续执行,是正当的。 // 不思考并发,不思考雷同key只执行一次,这里是能够的,如果要思考的话,这里可能会被执行两次 timer.item.removed = true newItem := &timingEntry{ baseEntry: task, value: timer.item.value, } tw.slots[pos].PushBack(newItem) tw.setTimerPosition(pos, newItem) }}//最初看一下是怎么删除的,其实这外面只是通过索引找到这个task,而后把task标记为删除。//下面看scanAndRunTask办法的时候曾经看到了解决被删除的节点的逻辑func (tw *TimingWheel) removeTask(key interface{}) { val, ok := tw.timers.Get(key) if !ok { return } timer := val.(*positionEntry) timer.item.removed = true tw.timers.Del(key)}

February 19, 2022 · 3 min · jiezi

关于golang:Golang-开源流媒体音视频网络传输服务LAL

一. lal 简介lal是开源直播流媒体网络传输我的项目,次要由三局部组成: lalserver:流媒体转发服务器。相似于nginx-rtmp-module等服务,但反对更多的协定,提供更丰盛的性能。demo:一些小利用,比方推、拉流客户端,压测工具,流剖析工具,调度示例程序等。相似于ffmpeg、ffprobe等利用。pkg:流媒体协定库。相似于ffmpeg的libavformat等库。以下是lal源码架构图,从中你能够大抵理解lal是如何划分性能档次的: lal github地址: https://github.com/q191201771...二. lalserver 疾速开始1 编译形式1,从源码自行编译 $git clone https://github.com/q191201771/lal.git$cd lal$export GO111MODULE=on && export GOPROXY=https://goproxy.cn,https://goproxy.io,direct$make或者应用GoLand等IDE编译。 如果没有装置Go编译器,可参考《CentOS或macOS装置GoLang》,windows操作系统可自行上网搜寻教程。 形式2,间接下载编译好的二进制可执行文件 点我关上《github lal最新release版本页面》,可下载linux/macos/windows平台编译好的lal二进制可执行文件(zip压缩包模式)。 形式3,应用docker docker又分为两种形式,一种是间接从Docker Hub下载曾经编译好的镜像并运行: $docker run -it -p 1935:1935 -p 8080:8080 -p 4433:4433 -p 5544:5544 -p 8083:8083 -p 8084:8084 -p 30000-30100:30000-30100/udp q191201771/lal /lal/bin/lalserver -c /lal/conf/lalserver.conf.json另一种是依据本地代码和Dockerfile文件生成镜像并运行: $git clone https://github.com/q191201771/lal.git$cd lal$docker build -t lal .$docker run -it -p 1935:1935 -p 8080:8080 -p 4433:4433 -p 5544:5544 -p 8083:8083 -p 8084:8084 -p 30000-30100:30000-30100/udp lal /lal/bin/lalserver -c /lal/conf/lalserver.conf.json2 运行$./bin/lalserver -c conf/lalserver.conf.json3 体验性能lalserver服务启动后,就能够进行推拉流了。 ...

February 19, 2022 · 4 min · jiezi

关于golang:Leetcode专题数组34在排序数组中查找元素的第一个和最后一个位置

力扣链接:https://leetcode-cn.com/probl...解题思路: 有序数组+logn的配置,应该首先想到的就是二分查找首先应用GO语言的个性函数sort.SearchInts函数,从切片中返回数组的下标,这里如果存在返回的是第一个等于target的下标,如果不存在,那么当x找不到时就会返回比x大的数的index,如果不存在比x大的数,那么返回的就是切片a的长度func searchRange(nums []int, target int) []int { left := sort.SearchInts(nums, target) if left == len(nums) || nums[left] != target { return []int{-1, -1} } right := sort.SearchInts(nums, target + 1) - 1 return []int{left, right}}3.解法二:不应用曾经封装好的函数的话,就须要本人实现二分查找,这里二分查找是十分罕用的,做一个总结,加深印象: (1)找下界:应用二分查找查问第一个等于target的数组下标,即在有序数组中,X>=target的下边界,在该边界的右边,所有数字都小于target,左边所有数字都大于target,实现如下:func searchLeft(nums []int, target int) []int { n := len(nums) l, r := 0, n-1 // 查找区间不能为空 for l <= r { mid := (r - l) >> 1 + l if nums[mid] >= target { r = mid - 1 } else { l = mid + 1 } if l == len(nums) || nums[l] != target { return []int{-1, -1} } return l}(2)找上界:在有序数组中x>=target的上界,和x>target的下界是相邻的,所以找上界的问题,能够推导为找x>target的下界,代码跟下面的雷同,就是判断条件编了func searchRight(nums []int, target int) []int { l, r := 0, len(nums) - 1 for l <= r { mid := (r - l) >> 1 + l if num[mid] > target { r = mid - 1 } else { l = mid + 1 } } if r < 0 || nums[r] != target { return []int{-1, -1} } return r // 因为循环到最初r比l小1,正好是等于target}

February 19, 2022 · 1 min · jiezi

关于golang:第二十四期golang-一年经验开发-富途

他们家是按题目来的,从一个小题目缓缓延长着问,由浅入深,问到你换题为止。 第一题 给了一个网址,解释一下浏览器填入这个网址后产生了什么?TCP为什么要三次握手四次挥手?502是什么?如果呈现502怎么办?怎么排查?为什么会呈现这个问题?好,如果你是开发,这个是你的服务,你怎么晓得你的服务出问题了?如果状况极其一点,你忽然间所有的服务都有问题了,但霎时又重启了,你如果不看日志,怎么晓得你的服务挂了?第二题 给了2个表构造,写sql。怎么优化?索引是什么?索引怎么加?如果状况极其一点,单表500W的数据量,写一条sql连表查前10条用户信息。怎么优化,怎么加索引?主键索引是什么?为什么要加主键索引?事务有哪些级别?Innodb和myisam的主键索引有什么区别?B树和B+树有什么区别?如果数据量再大一点,达到千万级别。预计加一条索引须要20分钟,你要怎么解决让他疾速加上去?如果分表怎么分?主从库怎么做,原理是什么?第三题 算法题,写个算法实现一个样例。这个算*在什么状况下用到呢?这个算法其实不是leetcode的算法题。我抽到的是签名算法的一个变种,须要长期实现一下。次要就是遍历递归+md5,而后解释利用场景。 富途的这个面的是最久的,愣是面了1个小时,而且很细,面到最初心态真的有点顶不住。之前也没体验过边写代码边聊问题的面试模式,犯了很多错,简直是面完我就晓得我凉了。

February 19, 2022 · 1 min · jiezi

关于golang:Go-开发团队技术-leader-Russ-Cox-发文分享-Go-的版本控制历史

Russ Cox (rsc)发现每隔一段时间总会有人示意Go 的首次 commit 是在 1972 年 。rsc认为这种说法显然是十分愚昧的,并分享了对于 Go 版本控制的更多乏味历史。例如: Go 真正首次 commit 是第 5 个 commit,此前的都是假 commit。 % git log --reverse --statcommit 7d7c6a97f815e9279d08cfaea7d5efb5e90695a8Author: Brian Kernighan <bwk>AuthorDate: Tue Jul 18 19:05:45 1972 -0500Commit: Brian Kernighan <bwk>CommitDate: Tue Jul 18 19:05:45 1972 -0500 hello, world R=ken DELTA=7 (7 added, 0 deleted, 0 changed) src/pkg/debug/macho/testdata/hello.b | 7 +++++++ 1 file changed, 7 insertions(+)...据rsc 所言,Go 应用过的版本控制系统共有 4 个:Subversion、Perforce、Mercurial 、Git。 commit 18c5b488a3b2e218c0e0cf2a7d4820d9da93a554Author: Robert Griesemer <gri@golang.org>AuthorDate: Sun Mar 2 20:47:34 2008 -0800Commit: Robert Griesemer <gri@golang.org>CommitDate: Sun Mar 2 20:47:34 2008 -0800 Go spec starting point. SVN=111041 doc/go_spec | 1197 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1197 insertions(+)SubversionGo 开始应用 Subversion 是作为评估Subversion在Google外部推广应用的可行性试验,尽管最初没有抉择 Subversion,但正是 Go 真正首次 commit提交到了 SVN 服务器。 ...

February 19, 2022 · 3 min · jiezi

关于golang:Go语言中的次方表示

1 起因刚接触Go语言后,开始着手用Go写算法题,想写个2的3次方,发现C语言学的2^3不能用了 a := 2 ^ 3 运行后果为1而不是想要的8 2 起因一查才发现,Go语言中符号 “ ^ ” 不再用于次方,而是示意“按位异或的运算”,具体的运算规定如下: 按位异或 ^ : 两位一个为 0, 一个为 1 ,后果为 1 ,否则为 0(位示意二进制的机器码),例子如下: 2 ^ 32 的补码 0000 00103 的补码 0000 00112 ^ 3 0000 0001 => 1所以Go语言中2 ^ 3 = 1 而不是 8(留神:计算机都是依照补码进行运算) 3 Go 的次方实现3.1 一般状况Go 语言实现次方的计算,咱们调用了 math.Pow 函数,math.Pow(x, y) 这样就能够求出 x 的 y 次方 以2的3次方为例: a := math.Pow(2, 3) 3.2 非凡状况当遇到要求 2 的 n 次方的时候,咱们能够使用 Go 语言的左移运算符 << ,实现左移运算。 ...

February 19, 2022 · 1 min · jiezi

关于golang:Golang-修改切片数据为什么会影响到其他切片的数据

发现问题:当用golang刷一道LeetCode题目时,78.子集,发现数据始终对不上,打印数据发现,居然有数据反复错误代码: var ans [][]intfunc dfs(nums []int, nowNums []int, l, r int) { ans = append(ans, nowNums) if l == r { return } for i := l; i < r; i++ { dfs(nums, append(nowNums, nums[i]), i+1, r) }}func subsets(nums []int) [][]int { ans = [][]int{} lenNums := len(nums) dfs(nums, []int{}, 0, lenNums) return ans}排查问题发现,nowNums切片在appen进ans后,居然还产生了扭转,导致原先不同数据变为雷同问题剖析:当dfs的形参用这种时 dfs(nums, append(nowNums, nums[i]), i+1, r)等价与上面这种 x := append(nowNums, nums[i])dfs(nums, x, i+1, r)咱们都晓得,切片是会主动扩容的,以后容量有余时,会主动依据最佳状况进行扩容(这里就不开展了),然而要晓得一点,扩容是从新申请一块内存,也就是说之前的内存没有用上了,看看这个例子代码: s1 := make([]int, 1, 1)s1[0] = 10s2 := s1fmt.Printf("%p,%p\n", s1, s2)fmt.Println(s1, s2)s2 = append(s1, 10)fmt.Printf("%p,%p\n", s1, s2)fmt.Println(s1, s2)输入:能够发现,s1数组在s2批改后是没有变动的,因为s2从新申请了一块内存空间,没有用s1的,所以s1不受影响哪这个不就保障了操作一个切片,另一个切片不受影响吗,跟问题有啥关系,甚至是解决了问题!然而,这是在扩容的状况下,要是没扩容呢?没扩容,s2的批改就会影响s1的数据,这就导致了方才题目的数据产生错乱,起因就是nowNums切片没有扩容,导致曾经进入ans的切片数据,在后续的递归中还会产生更改。怎么解决这个问题,最好的办法是间接取出以后切片的数据,管它后续会不会产生更改代码: ...

February 19, 2022 · 1 min · jiezi

关于golang:golangleetcode中级数组中的第K个最大元素寻找峰值

第一题 数组中的第K个最大元素题目 解题简略的排序函数+定位代码 func findKthLargest(nums []int, k int) int { sort.Ints(nums) return nums[len(nums)-k]}复杂度剖析 工夫复杂度:O(nlogn)。sort的排序函数复杂度最坏状况均为O(nlogn) 空间复杂度:O(1) sort大部分排序的实现都是在原数组的根底上原地实现的 对于sort包的剖析 https://www.cnblogs.com/dongj... 第二题 寻找峰值题目 解题思路 对于数组首元素和尾元素为最大值的状况因为默认nums[-1] = nums[n] = -∞因而这两个元素一样是峰值 代码func findPeakElement(nums []int) int { n := len(nums) // 辅助函数,输出下标 i,返回 nums[i] 的值 // 不便解决 nums[-1] 以及 nums[n] 的边界状况 get := func(i int) int { if i == -1 || i == n { return math.MinInt64 } return nums[i] } left, right := 0, n-1 for { mid := (left + right) / 2 if get(mid-1) < get(mid) && get(mid) > get(mid+1) { return mid } if get(mid) < get(mid+1) { left = mid + 1 } else { right = mid - 1 } }}复杂度剖析工夫复杂度:O(logn),其中 n 是数组 nums 的长度。 ...

February 18, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组33搜索旋转排序数组

力扣链接:https://leetcode-cn.com/probl...解题思路: 题目要求设计一个O(logn)工夫复杂度的算法,数组+O(logn)基本上能够确定是应用二分法来解决对旋转后的数组进行剖析,找法则,能够发现,选定一个数字,将数组分成前后两个局部,其中一个局部必然是有序的应用二分法,先从中位数开始找,最重要的是左右边界的膨胀,依据trget所处的地位进行膨胀即可确定中位数字之后,咱们须要断定有序区间,因为只有在有序区间外面咱们才不便比拟数字在不在外面 (1)如果mid的左半边有序,那么很容易就能够断定target是不是在左半边,如果在,high = mid -1;如果不在,low := mid +1 (2)如果mid的右半边有序,那么很容易就能够断定在不在右半边,如果在那么low = mid + 1,如果不在那么high = mid -1 (3)须要留神的是low和high的取值,因为有可能这个数字在数组的第一个地位,那么high和low是有可能想等的,同时mid也有可能是和low及high想等的,边界条件判断须要清晰func search(nums []int, target int) int { n := len(nums) low, high := 0, n - 1 for low <= high { mid := (high - low) >> 1 + low if nums[mid] == target { return mid } if nums[low] <= nums[mid] { // 左半边有序 if nums[low] <= target && target < nums[mid] { high = mid - 1 } else { low = mid +1 } } else { // 右半边有序 if nums[mid] < target && target <= nums[high] { low = mid + 1 } else { high = mid -1 } } } return -1}

February 18, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组31下一个排列

力扣链接:https://leetcode-cn.com/probl...解题思路: 第一次接触这个算法,没想到C++的STL库中就有next_permutation这个算法,用于计算下一个字典序列,这个算法自身也是十分精妙,没有其余额定的,记住这个算法就能够了回归到题目自身,首先第一步就是从后往前遍历数组,找到第一个不为降序的数字,也就是对于下标i < i + 1; 有 a[i] > a[i+1];将此数记为a,此时i+1 ~ n-1的数字均为降序持续从后往前遍历,找到第一个大于a[i]的数字,记为b而后将a和b进行调换从a+1到n此时为降序,能够应用二分翻转翻转数组,使其成为升序(也能够间接排序)// 解题思路// 1、从后向前找到第一个非降序的数,即i < i+1 && a[i] < a[i+1]// 2、从后往前找到第一个大于a[i]的数a[j]// 3、替换a[i]和a[j],此时i+1~n肯定是降序的// 4、将i+1后的数字翻转排序func nextPermutation(nums []int) { n := len(nums) i := n - 2 for i >= 0 && nums[i] >= nums[i+1] { i-- } if i >= 0 { j := n-1 for j >= 0 && nums[i] >= nums[j] { j-- } nums[i], nums[j] = nums[j], nums[i] } reverse(nums[i+1:])}func reverse(nums []int) { for i, n := 0, len(nums); i < n / 2; i++ { nums[i], nums[n-1-i] = nums[n-1-i], nums[i] }}

February 18, 2022 · 1 min · jiezi

关于golang:第二十三期春招实习阶段性总结阿里云已OC

自己算是一个科班出身找工作的菜鸡了,当初手中阿里云云原生offer、百度度小满offer、腾讯PCG二面环节、美团点评等offer环节。心愿我的经验分享能对各位或之后筹备春招的同学有帮忙。 集体背景自己某985本科软工科班出身,在读研和工作之间始终有着很强烈的抉择。之前是始终筹备读研的,处于保研边缘但保不上研的那种垃圾。暑假开始刷考研数学的习题,春节前三天停下了刷题的脚步加入了美赛,那时曾经过了十几章了。美赛之后我趁年关对本人从新扫视了一下,因为之前始终是做两手筹备,一边打算考研,一边同时也在看工作的货色,看了差不多一个月了吧,所以感觉进度都差不太多,然而务必得确定一个次要方向了。说实话,考研数学不能让我提起半点趣味,我读研的目标又只是为了混一个学历而已,我要花费近一年的工夫去做这些让我十分煎熬的事件去换一个并不很值得的学历,而且我又属于大考必失误的体质(高中分班考试失误、高考失误少考将近40分),所以我就抉择了工作这条路。 方向抉择咱们实验室的那几个找工作的都是卷怪,不晓得在一年前就开始了筹备,所以我感觉得凸显本人的劣势,不能和他们硬碰硬。Java卷疯了,前端我也不喜爱,C++耗命,所以Golang是一个很好的抉择。因为我大二参加实验室的区块链课题钻研,所以Golang有根底的。Golang的话根本各种云服务、腾讯的PCG、字节等的都会用,然而和Java的大需要还是不能比,所以转栈需谨慎。我扫视了我的大学近3年,实验室的几个纯业务的我的项目、几个科研性质的我的项目、大三搞了半年的学术论文(其中一篇幸运沾老师的光发了SCI)(不想读研的又一重要起因)、数模以及其余翻新守业的较量。。。如同也没啥了。那就这样吧,硬着头皮上。 春招筹备简历很重要,所以过后我就把我的所有这个那个的奖、这个那个的较量还有这个那个的论文都写上去了,我的项目加了一番包装也写上去了,乍一看还像那么回事。而后就是筹备面试了,之前用Java写的后端都模仿用Golang做一下(仅仅模仿一下业务,不是真的重构),而后用Beego搭了个博客,把本人之前做的比拟唬人的货色写上去了,的确还有那么点意思。书的话《Go语言编程》打基础、《Go并发编程实战》、《Go语言圣经》、《Go语言实战》用作晋升。Golang就看下面这些应该差不多,再就是八股文,计算机网络的话《网络是怎么连贯的》和《计算机网络-自顶向下办法》(上课的课本)很够用了,操作系统的话《深刻了解计算机系统》和《操作系统概念》(课本)也就差不太多了。数据库的话《深入浅出Mysql》、《Mysql必知必会》、《数据库系统概念》,也就差不太多了。书方面我就看了这些。其余的很多货色是博客上看的,linux常用命令、I/O相干、Golang内存模型、内存调配、GC、Redis相干、分布式相干等,就是面经上有啥就看啥。而后为了防止面试问我论文与我的项目相干,我又筹备了和之前钻研方向相干的一些面试题(发现算法岗是真的卷)。差不多就这些了,再就是每次面试之后一直减少本人不相熟的货色。 开始面试我首先就投了阿里云和字节后端,是正月初七开始投的,很多大哥年前就开始投了(太猛了)。都说字节效率高,然而我好久没收到面试告诉(可能因为我菜)。阿里云的大佬们很快就约了我,我同时和云原生的三个团队进行分割,两个是容器的团队,一个是数据可视化的如同。(提前批能够广投当海王,而后最初选一个进零碎)流程最快的还是其中一个容器团队,最初我也收到这个团队的offer,所以我就说说这个团队的经验。 一面自我介绍TCP/UDP区别TCP拥塞管制流量管制HTTPS原理过程make原理过程线程协程区别各自构造内存调配分布式CAP模型golangGMP模型golang内存调配golang GC(三色、写屏障、STW)linux io多路复用(epoll、poll、select)linux io流程(利用、文件系统、内核、硬件)程序编译的流程、执行的流程、外部状态(深刻了解计算机系统中有)算法(合并升序链表、长数字划分多个能够被3整除的数)(人生中第一次面试,答的自我感觉还算良好)二面自我介绍我的项目介绍针对一个我的项目问(并发量、业务流程、我所做的工作、技术挑战点)针对一个钻研性质的我的项目问(怎么抉择分类器、数据量、工作流程、数据结构)JVM I\O时操作系统产生了什么算法(链表是否有环、走楼梯)(阿里的算法是真的不难,然而对我的项目是真的器重)三面过后我在洗头,忽然就来电话了,迅速三面问我的每一篇论文别离是干啥的每一篇论文做的货色别离啥每一篇我的工作别离是啥因为我的论文大多数是网络嵌入相干的,我就介绍了我主写的那篇我搭的神经网络的准则、大抵构造、性能等相干的货色还有钻研性质我的项目上用的算法相干的问题面试官间接告诉我提前批通过,三月中旬等音讯3.5 进零碎录信息,测评+口试 3.8 下午时候忽然又接到电话,三面面试官打来的,说要加一面 四面自我介绍每个我的项目都简略介绍介绍学习状况实验室状况论文状况实习工夫而后最离谱的是让我用英文介绍TCP/IP协定栈,我间接以英文书面语不好拒绝了,有点离谱好吗而后说挺不错的等下次面试告诉,还有让我回去好好学英语 (而后就是漫长的HR面试期待,开始两周一催,前面一周一催) 4.5 痛哭流涕,HR太令人感动了,占用假期工夫面试我。奖项介绍经验介绍我的项目中的角*r>将来打算等等等(感觉还是不错的,阿里云的HR面虽慢尤强) 4.6 意向书收到(还愿还愿)百度度小满的面经先不说了吧,过程比起其余的顺利多了,等过几天想写的时候再加到后边,字节是和一个部门面试了一次,而后卡我简历,春招才通知我挂了,而后得走春招流程加入口试,而后加入了两次口试了,还是没约面试(真的是我太菜了)。腾讯的更波折,WXG三面挂、财经三面挂(该生根底扎实、算法能力强、逻辑能力强,然而倡议读个研究生,倡议不通过),还让我转C++,节约我的感情,当初终于面了一个Golang的岗位了,PCG的,过几天看情绪随缘分享吧,美团点评是用Golang去面Java后端岗,面试总之不是很难受,毕竟转岗面试竞争大难度也大。总体总结一下,应用Golang面其余岗有点难,须要看的挺多,然而如果面Golang后端开发就很难受了。如果筹备找工作,而且对Golang感兴趣,能够抉择Golang,然而这个能够抉择的岗位不是很多,究竟和Java没法比,Java是只有致力了卷了就肯定有播种,而Golang就是能够抉择的岗位不多,须要专精须要宽泛抉择,综合能力跟上。我在春招期间真的播种挺大的,原来认为抗压能力还行,起初发现我的心态真的不如我想的好,就在等阿里HR面途中,腾讯搞人心态,而且也没有其余的面试告诉时,真的一度超级好受,都开始从新拿起考研教材了,起初也是和朋友家人聊天缓解过去了,我一受挫就海投,什么京东、BiliBili、360、搜狗、小米等都投过,只是想拿个保底,毕竟Golang岗要想的的确比其余岗要多,不是卷就能成的。然而它们的流程仿佛很慢,在收到offer后我就都拒了它们的邀请了,终于算躺平了吧。

February 18, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组18四数之和

力扣链接:https://leetcode-cn.com/probl...解题思路: 之前尝试过很多刷题的办法,一方面感觉是本人的技术积攒和对语言的理解使用的确还差火候,另一方面是刷题的思路不对,依照题目程序来刷或者单纯依照难度来刷都有其缺点,首先依照题目程序来刷,实际上每个题目的知识点都不雷同,东一榔头,西一棒槌,很难系统性的学习某个知识点,依照难度来耍,一开始就上mid或者hard的题目,很快就会因为畏难而造成刷题效率大打折扣。这次采纳了新的办法,首先分门别类,如数组/链表/树/动静布局等,而后每个类别先从简略刷题,每个类别每个难度刷20道题。通过一段时间的验证当前,有事倍功半的成果回到这道题自身,三数之和/最靠近的三数之和/四数之和,实质上都是采纳一种办法,那就是排序+双指针,最初两位数肯定是双指针,那么后面残余的数字就是须要循环遍历的这道题为了优化一个不须要的便当,对边界做了一些优化,当然这些都是小优化,不扭转实质的算法func fourSum(nums []int, target int) [][]int { n := len(nums) sort.Ints(nums) ans := make([][]int, 0) for i := 0; i < n-3 && nums[i]+nums[i+1]+nums[i+2]+nums[i+3] <= target; i++ { if i > 0 && nums[i] == nums[i-1] || nums[i]+nums[n-1]+nums[n-2]+nums[n-3] < target { continue } for j := i + 1; j < n-2 && nums[i]+nums[j]+nums[j+1]+nums[j+2] <= target; j++ { if j > i+1 && nums[j] == nums[j-1] || nums[i]+nums[j]+nums[n-1]+nums[n-2] < target { continue } k, l := j+1, n-1 for k < l { sum := nums[i] + nums[j] + nums[k] + nums[l] if sum == target { ans = append(ans, []int{nums[i], nums[j], nums[k], nums[l]}) for k++; k < l && nums[k] == nums[k-1]; k++ { } for l--; k < l && nums[l] == nums[l+1]; l-- { } } else if sum > target { l-- } else { k++ } } } } return ans}

February 18, 2022 · 1 min · jiezi

关于golang:golangleetcode中级颜色分类前K个高频元素

第一题 色彩分类题目 解题思路 代码//三指针func sortColors(nums []int) { //0的右边界 left := 0 //2的左边界 right := len(nums) - 1 //指向以后数字 index := 0 for index <= right { if nums[index] == 0 { //如果是0,就往前面移 swap(nums, left, index) left++ index++ } else if nums[index] == 1 { index++ } else if nums[index] == 2 { //如果是2就往后面移 swap(nums, right, index) right-- } }}//替换数组中的两个数字func swap(nums []int, i int, j int) { nums[i], nums[j]= nums[j],nums[i]}后果如下 ...

February 17, 2022 · 3 min · jiezi

关于golang:Leetcode专题数组16最接近的三数之和

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题的解题思路跟三数之和雷同,都是:排序+双指针首先将数组排序,而后初始化三数之和为数组的前三个元素而后标的i第一个数字开始遍历,如果遇到雷同的数字就跳过,后两位数字为双指针,别离是i后的第一个数字和数组的最初一个数字当两个指针相遇之前,计算三个数的和,记录跟target绝对值最小的和,如果想等间接返回 func threeSumClosest(nums []int, target int) int { sort.Ints(nums) n, closeSum := len(nums), nums[0] + nums[1] + nums[2] for i := 0; i < n - 2; i++ { if i > 0 && nums[i] == nums[i-1] { continue } j, k := i+1, n-1 for j < k { sum := nums[i] + nums[j] + nums[k] if sum == target { return target } if abs(closeSum - target) > abs(sum - target) { closeSum = sum } if sum > target { k-- } else { j++ } } } return closeSum}func abs(x int) int { if x > 0 { return x } return -x}

February 17, 2022 · 1 min · jiezi

关于golang:Go语言中fmtPrintlntrue的结果一定是true么

背景Honeycomb的首席开发布道者Jessica在Twitter上发了一条状态: fmt.Println("What is truth?", true) can output: What is truth? false 意思是上面代码的执行后果可能是What is truth? false fmt.Println("What is truth?", true)大家能够先想想什么状况下会呈现这样的后果。 解析咱们来看上面这段代码: // identifier.gopackage mainimport "fmt"func main() { true := false fmt.Println(true)}大家感觉这段代码是会编译报错呢,还是失常执行? 理论执行后果是打印false,并不会编译报错。 因而本文结尾的代码fmt.Println("What is truth?", true)是可能打印What is truth? false的。 有的同学可能好奇了?为什么会这样呢?true不是Go语言的关键字么,为什么还能够定义标识符为true 的变量? 答案是:true 并不是Go语言的关键字,Go语言目前只有25个关键字,如下所示: break default func interface selectcase defer go map structchan else goto package switchconst fallthrough if range typecontinue for import return var这些关键字是不能够用来作为Go语言的标识符的。true是预申明标识符,是能够作为Go语言的标识符的,官网阐明如下: Predeclared identifiersThe following identifiers are implicitly declared in the universe block: ...

February 17, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组15三数之和

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题跟之前的两数之和有点像,然而解法哈难度都齐全不一样了,mid的题目相应来说还是须要刻意训练来把握的,相似三数之和这样的题目,如果不懂解法,可能无论怎样致力也无奈失去冀望的解学习本人么有思路的题目时,能够先从模拟开始,就像书法巨匠,绘画巨匠,无一不是从临摹拓字开始的,学习,强化,记忆,而后融汇贯通持续分析题干,这道题其实最难的点在于三元组不能反复,那么咱们能够将数组排序,这样就不会有反复的三元组,接下来咱们首先确定a,即最里面的一轮循环,而后b和c能够应用双指针来进行优化,最初要留神边界条件:a/b/c都不能反复,遇到雷同的值间接跳过,b <= c等等要害思路:排序+双指针优化func threeSumm(nums []int) [][]int { n := len(nums) sort.Ints(nums) ans := make([][]int, 0) // 枚举a for first := 0; first < n; first++ { // 跟上次的数字雷同则跳过 if first > 0 && nums[first] == nums[first-1] { continue } // c对应的指针在数组的最右端 third := n - 1 target := -1 * nums[first] // 枚举b for second := first + 1; second < n; second++ { // 跟上次的数字雷同则跳过 if second > first+1 && nums[second] == nums[second-1] { continue } // 须要保障b在c的右侧,同时两个数的和大于target的相反数 if second < third && nums[second]+nums[third] > target { third-- } // 如果b等于c的时候还没有想等的数组,那么随着b的增大,则更不会有了 if second == third { break } if nums[second]+nums[third] == target { ans = append(ans, []int{nums[first], nums[second], nums[third]}) } } } return ans}

February 17, 2022 · 1 min · jiezi

关于golang:Golang协程和channel使用

简介协程是golang的一大特色和卖点. 协程(goroutine) 是轻量级的执行线程,应用go关键字到函数或者lamba表达式能够疾速启动协程.协程函数的返回值会被摈弃.线程的调度由操作系统来治理,是抢占式调度。而协程不同,协程须要互相配合,被动交出执行权。 配置GOMAXPROCS 设置逻辑CPU数量,个别状况下应用CPU外围数量值.应用足够的线程来进步golang的并行执行效率.如果你的业务是IO密集型则能够设置数倍与CPU外围数的值来失去更好的性能.如果Go程序在容器中执行则须要依据状况缩小该值得,因为容器中无奈应用到宿主机的全副外围.设置更小的值能够防止线程切换的开销. 应用channel进行协程通信定义通道ch1 := make(chan string) //定义了一个无缓冲的string通道ch2 := make(chan string , 4) //定义了一个4个元素的string通道通道操作符ch1 <- "Chengdu" //向通道写入数据itemOfCh1 := <- ch1 //从ch1通道读取一条数据<- ch1 //读取通道的下一个值var in_only chan<- int //只能接管通道var out_only <-chan int //只读取的通道close(ch) //敞开通道通道阻塞默认状况通道是同步无缓冲的,在接受方未筹备好之前发送方是阻塞的.通道中没有数据则接管方也是阻塞的. package mainimport ( "fmt" "time")func f1(in chan int) { data := <-in fmt.Println(data)}func main() { out := make(chan int) out <- 2 fmt.Println(v) go f1(out) time.Sleep(100 * time.Millisecond)}以上程序会panic退出,因为out写入数据并没有接受者,因而main主协程被阻塞了.前面的代码永远不会被执行,因而通道永远不会有数据,产生了死锁.批改 out:=make(chan int , 1) 让通道有一个缓冲则不会死锁.或者在写入前启动读取的协程.或者在另外一个协程来读取都能够解决这个问题.应用信号量能够通过信号量来让主协程期待子协程的实现退出执行. package mainimport ( "fmt" "time")func f1(in chan int, done chan int) { data := <-in fmt.Println(data) time.Sleep(10e9) done <- 1}func main() { out := make(chan int) done := make(chan int) go f1(out, done) out <- 2 <-done}输入 2 之后10秒后程序才会退出,咱们就不须要应用sleep来让主过程执行. ...

February 17, 2022 · 2 min · jiezi

关于golang:Leetcode专题数组11盛雨水最多的容器

力扣链接:https://leetcode-cn.com/probl...解题思路: 接雨水这个问题算是数组中比拟经典的问题,还是先指出要害算法:双指针接下来还是老办法,分析题干,由题目可知,因为数组的下标能够看作是横坐标,数组的值能够看作是纵坐标,所以盛雨水最多,实际上是数组中能够围成的最大面积,那么这个最大面积如何计算呢?就是长*高,即数组下标和值所能围成的最大面积采纳双指针,慢指针指向数组头,快指针指向数组尾部,面积为快指针下标-慢指针下标与两个下标中较小的高度乘积,记录这个值,当有更大的时候替换这个值数组如果遍历,那天然是较矮的往两头挪动,直到两个指针相遇func maxArea(height []int) int { n := len(height) l, r, max := 0, n-1, 0 for l < r { m := (r - l) * min(height[l], height[r]) if max < m { max = m } if height[l] < height[r] { l++ } else { r-- } } return max}func min(x, y int) int { if x < y { return x } return y}func max(x, y int) int { if x > y { return x } return y}

February 17, 2022 · 1 min · jiezi

关于golang:第二十二期Shein云平台一面二面面经

一面意外的没有自我介绍,间接就开始问我的项目 介绍我的项目Go根底Go有哪些数据结构Go的数据结构的零值是什么切片是怎么扩容的Go中new和make的区别make能够初始化哪些构造理解过channel吗channel外部数据结构有理解吗有缓冲和无缓冲的区别假如向敞开的channel写或读会产生什么panic和error理解过吗panic如何解决间断敞开两次管道会产生什么理解过Go的内存治理吗简述下GC原理和过程简述下GMP模型和调度过程数据结构简述下理解的排序算法说一说你最相熟的排序算法的过程和复杂度Docker简述下Docker简述下你个别用Docker干什么理解过k8s吗MySQL隔离级别简述下事务Where和Having的区别反诘我问得想更深刻理解公司和云平台部门小结总耗时30分钟左右,面试官是个小哥哥,声音听下来很年老,我遇到说错的中央的时候也会提醒我例如敞开的Channel那里我说反了也提醒我说反了。意外的没有要求手写代码,而是口头简述代码和简单有点意外 总的来说shein的云平台部门很看重语言根底,问了很多货色,相比我筹备了许久的数据库简直没什么问而且我还答的十分不好(最初那个我甚至忘光了)。 二面二面出其不意,看来的确有点缺人,基本上在聊天,很轻松。首先是自我介绍,而后问本科是什么,为什么没加入秋招,研究生考试如何,考得哪里的研究生。而后问本科你感觉最重要的三门课是什么,为什么。 而后问玩不玩游戏,如果有个180g的游戏但电脑只有4g内存,你要如何加载这个游戏,操作系统会产生什么问题。问页面置换是什么,有哪些算法,聊一聊LRU怎么实现,最初问了问快排思维 结尾问喜爱看书么,看什么类型的书,最初反诘阶段 面试官很nice,最初还说如果考上研想实习能够来找他,也加了微信,整个过程只有15分钟……

February 17, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组283移动零

力扣链接:https://leetcode-cn.com/probl...解题思路: 这道题尽管比较简单,然而其实也是十分奇妙的,能够用双指针的解法首先定义快慢两个指针,初始化都为数组的第一个元素,快指针遍历整个数组,遇到不为0的数字,跟慢指针调换地位,此时慢指针加一,如果进入不了整个不为0的条件,那么快指针加一这样就保护了一个慢指针和快指针之间的为0的窗口,始终到最初func moveZeroes(nums []int) { n := len(nums) low, high := 0, 0 for high < n { if nums[high] != 0 { nums[low], nums[high] = nums[high], nums[low] low++ } high++ }}

February 16, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组268丢失的数字

力扣链接:https://leetcode-cn.com/probl...解题思路: 还是老套路,看题干,找线索,首先题干给的是蕴含[0,n]的数字数组,找出[0,n]中没有呈现在数组中的数字。那么如果[0,n]中所有的数字全副都在,就肯定是形如[0,1,2,3,4...,n-1,n]这样的相邻递增数字找法则:在这样的数字中,首先对其进行排序,排序后下标和数字是相等的,那么首先就能够对数组进行遍历,如果遍历到某个下标,数字跟它不相等,则该数字不存在func missingNumber(nums []int) int { for i, v := range nums { if i != v { return i } } return len(nums)}3.下面的思路能够进一步延长,应用哈希表进行优化,首先将每个数组中的数字以数字为KEY,TRUE为value进行标记,而后进行一个从0~下限的遍历,m[i]为false时则这个数字是缺失的 func missingNumber(nums []int) int { numToBool := make(map[int]bool, len(nums)) for i := 0; i < len(nums); i++ { numToBool[nums[i]] = true } for i := 0; ; i++ { if !numToBool[i] { return i } } return len(nums)}4.最精妙的解法,害得是数学!从小咱们就晓得高斯这个数学小王子,得出了从0~n的整数和的公式:sum = n * (n + 1) / 2;那么从0到n的数字,缺失的就是应该有的数减去数组之和: ...

February 16, 2022 · 1 min · jiezi

关于golang:Leetcode专题数组228汇总区间

力扣链接:https://leetcode-cn.com/probl...解题思路: 汇总区间这个题目跟之前一个输入排序区间的题目有点像。首次拿到这个题目,脑海中先想到的就是双指针的做法,先选定算法,再剖析细节在抉择双指针之后,首先要确定遍历对象,那就是整个数组,通过循环来遍历整个数组起始时双指针均位于数组的第一个元素,而后快指针开始遍历,直到找到第一个不间断递增的数字,而后再和慢指针的下标做比拟,如果此时快慢指针相等,那么阐明这个区间中只有一个数字,退出数组即可。如果快指针大于慢指针,那么插入区间最初更新指针,快指针加一,慢指针等于快指针,开始下一轮循环直至完结func Summary(nums []int) []string { n := len(nums) if n == 0 { return []string{} } low, high := 0, 0 ans := []string{} for high < n { for high < n-1 && nums[high]+1 == nums[high+1] { high++ } if low == high { ans = append(ans, strconv.Itoa(nums[low])) } else if low < high { ans = append(ans, strconv.Itoa(nums[low])+"->"+strconv.Itoa(nums[high])) } high++ low = high } return ans}

February 16, 2022 · 1 min · jiezi

关于golang:第二十一期知乎社招Golang工程师面经

一面分布式系统一致性说一下raft算法细节锁问题,cas,锁的实际?go规范库的mutex介绍bitcask存储模型细节,既然是追加写,那么如何做旧数据gc?重启后索引怎么复原?LSM tree介绍一下,相比b+ tree如何?给TIDB代码奉献介绍一下,TIDB里query大略流程?我的项目里的map并发怎么做?为啥用分段锁不必sync.map?分段锁拆了几个分片?内存对其理解吗?简略介绍一下go的内存分配机制?有mcentral为啥要mcache?答了mcentral是服务所有零碎线程,mcache为零碎线程独享,mcache短少span时去mcentral->mheap中取二面聊了聊开源奉献redis连环炮,数据结构+哨兵+同步聊工作我的项目innodb连环炮index redo undo mvcc闲聊技术人生问了问组里的工作hr聊人生聊倒退

February 16, 2022 · 1 min · jiezi