Giter VIP home page Giter VIP logo

interview-go's Introduction

interview-go's People

Contributors

baronwithyou avatar fengqi avatar hingbong avatar illidan33 avatar jau1jz avatar leechichuang avatar lifei6671 avatar liukgg avatar loverhythm1990 avatar metrue avatar natsuboy avatar quietin avatar quzard avatar rentiansheng avatar shd101wyy avatar silves-xiang avatar soolaugust avatar sulenn avatar tsunhua avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

interview-go's Issues

第二题中的一些疑问?

既然都是ASCII码,那长度大于256必定会出现重复的,所以改为以下是不是可以:

func isUniqueString(s string) bool {
	if len(s) > 256 {
		return false
	}

	unique := make(map[int32]bool)

	for _, v := range s {
		if v > 256 {
			return false
		}
		if _, ok := unique[v]; ok {
			return false
		} else {
			unique[v] = true
		}
	}
	return true
}

question/q001.md 优化

number, letter := make(chan struct{}), make(chan struct{}) letter <- struct{}{} 这种使用方式比 number, letter := make(chan bool), make(chan bool) letter <- true 更好些吧

语法找错题 最后一道解答错误

https://github.com/lifei6671/interview-go/blob/master/question/q014.md

下面代码写法有什么问题?

package main
import (
    "fmt"
)
type Student struct {
    Age int
}
func main() {
    kv := map[string]Student{"menglu": {Age: 21}}
    kv["menglu"].Age = 22
    s := []Student{{Age: 21}}
    s[0].Age = 22
    fmt.Println(kv, s)
}

-golang中的map 通过key获取到的实际上是两个值,第一个是获取到的值,第二个是是否存在该key。因此不能直接通过key来赋值对象-(错误解答)

是因为map中保存的是值类型 kv["menglu"] 操作是拿到map中的拷贝
如果换成 kv := map[string]*Student{"menglu": {Age: 21}} 使用指针就不会有问题

常见语法题目 一 的第6题,CAS操作

题目:
6、请说明下面代码书写是否正确。

var value int32

func SetValue(delta int32) {
	for {
		v := value
		if atomic.CompareAndSwapInt32(&value, v, (v+delta)) {
			break
		}
	}
}

解析:

atomic.CompareAndSwapInt32 函数不需要循环调用。

疑问:
atomic.CompareAndSwapInt32仅提供了原子交换的操作,我理解SetValue这个函数的用意应该就是让value加上delta大小的数值,所以在atomic.CompareAndSwapInt32操作失败,返回False的时候应该要循环重新读取新值然后进行CAS操作,直到atomic.CompareAndSwapInt32返回为True
解析中的不需要循环调用,是否描述不正确。

交替打印数字字母的另外一种实现方法

package main

import (
	"fmt"
	"runtime"
	"sync"
)

const N = 28

func main() {
	runtime.GOMAXPROCS(1)
	wg := &sync.WaitGroup{}
	wg.Add(N)
	for i := 0; i < N; i++ {
		go func(m int) {
			defer wg.Done()
			fmt.Printf(`%d%d`,m+1,m+2)
			runtime.Gosched()
		}(i)
		go func(m int) {
			defer wg.Done()
			if m == 26 {
				runtime.Goexit()
			}
			fmt.Printf(`%c%c`, 'A'+m, 'A'+m+1)
		}(i)
		i = i + 1
	}
	wg.Wait()
}

交替打印数字和字母 - 示例问题描述及优化

示例代码:

	letter,number := make(chan bool),make(chan bool)
	wait := sync.WaitGroup{}

	go func() {
		i := 1
		for {
			select {
			case <-number:
				fmt.Print(i)
				i++
				fmt.Print(i)
				i++
				letter <- true
				break
			default:
				break
			}
		}
	}()
	wait.Add(1)
	go func(wait *sync.WaitGroup) {
		str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

		i := 0
		for{
			select {
			case <-letter:
				if i >= strings.Count(str,"")-1 {
					wait.Done()
					return
				}

				fmt.Print(str[i:i+1])
				i++
				if i >= strings.Count(str,"") {
					i = 0
				}
				fmt.Print(str[i:i+1])
				i++
				number <- true
				break
			default:
				break
			}

		}
	}(&wait)
	number<-true
	wait.Wait()

这个代码正确得到了结果,但是代码它本身存在严重的瑕疵:

  • (重要)接收信号使用了 select default 模式, chan 没有数据时,陷入多余的循环,浪费硬件资源
  • (重要)没有正确关闭 number 与 letter 通道,这个简短的程序它运行没有问题,是等待 main 函数退出系统回收相关资源的
  • (重要)打印 number 的 goroutine 没有正确关闭,是等待 main 函数退出系统回收
  • (次要)低效率的字典模式打印字符串,需要预先创建需要打印字符的字典,然后按字典进行打印

Goroutine泄露问题——交替打印数字和字母

Goroutine是如何泄露的

在交替打印数字和字母的解法里面,负责打印字母的goroutine可以正常退出,但是负责打印数字的goroutine是一个死循环,因此示例代码存在泄露goroutine的风险

	go func() {
		i := 1
		for {
			select {
			case <-number:
				fmt.Print(i)
				i++
				fmt.Print(i)
				i++
				letter <- true
			}
		}
	}()

解决办法

负责打印字母的goroutine在退出时可以执行close(number)告知打印数字的goroutine退出

package main

import (
	"fmt"
	"sync"
)

func main() {
	letter, number := make(chan bool), make(chan bool)
	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		defer func() {
			fmt.Println("\nNumber goroutine exit.")
			wg.Done()
		}()
		i := 1
		for range number {
			fmt.Print(i)
			i++
			fmt.Print(i)
			letter <- true
		}
	}()

	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		defer func() {
			close(number)
			fmt.Println("\nLetter goroutine exit.")
			wg.Done()
		}()
		i := 'A'
		for range letter {
			if i >= 'Z' {
				return
			}

			fmt.Print(string(i))
			i++
			fmt.Print(string(i))
			i++
			number <- true
		}
	}(&wg)

	number <- true
	wg.Wait()
}

最长公共前缀 go版本代码有误

给出的实例代码中 内循环没有判断是否超过字符串长度,如果给出[]string{"flower", "flow", "flow"} 这样的输入直接就panic了。
建议修改为

for i := range firstStr {
		for j := 1; j < l; j++ {
			if len(arr[j]) == i || arr[j][i] != firstStr[i] {
				return firstStr[:i]
			}
		}
	}

”判断字符串中字符是否全都不同“错别字

原文:
第二个方法使用的是golang内置方法strings.Index和strings.LastIndex,用来判断指定字符串在另外一个字符串的索引未知,分别是第一次发现位置和最后发现位置

错别字:索引位置

实现阻塞读的并发安全Map

package main

import (
	"fmt"
	"time"
	"sync"
)

type sp interface {
	Out(key string, val interface{})  //存入key /val,如果该key读取的goroutine挂起,则唤醒。此方法不会阻塞,时刻都可以立即执行并返回
	Rd(key string, timeout time.Duration) interface{}  //读取一个key,如果key不存在阻塞,等待key存在或者超时
}


type Item2 struct {
	value interface{}
	ch    chan struct{}
	exist bool
}
type ConcurrentMap struct {
	mapval map[string]*Item2
	rwmutex  *sync.RWMutex
}

func NewConcurrentMap() *ConcurrentMap {
	return &ConcurrentMap{
		mapval: make(map[string]*Item2, 0),
		rwmutex:  new(sync.RWMutex),
	}
}

func (c *ConcurrentMap) Out(key string, val interface{}) {
	c.rwmutex.Lock()
	defer c.rwmutex.Unlock()

	item, ok := c.mapval[key]
	if !ok {
		c.mapval[key] = &Item2{
			value: val,
			exist: true,
		}
		return
	}

	item.value = val
	if !item.exist {
		if item.ch != nil {
			close(item.ch)
			item.ch = nil
		}
	}

	return
}

func (c *ConcurrentMap) Rd(key string, timeout time.Duration) interface{} {
	c.rwmutex.Lock()
	defer c.rwmutex.Unlock()

	item, ok := c.mapval[key]
	if !ok {
		item = &Item2{
			exist: false,
			ch: make(chan struct{}, 1),
		}
		c.mapval[key] = item
	}

	if item.exist {
		return item.value
	}

	select {
	case <-time.After(timeout):
		return nil
	item, _ = c.mapval[key]
	return item.value
}


func main() {
	mapval := NewConcurrentMap()
	mapval.Out("yanglei", "xx")
	mapval.Out("yanglei", "yy")

	fmt.Printf("%v\n", mapval.Rd("yanglei2", 5 * time.Second))
}

interview-go/question /q015.md

  1. Pool 内存不会暴涨。
    内存主要受256M协程影响。 定时501 ms 增长一次。因为它无法抢到pool中的buffer, 所以每次都要grow一份。
    估计最多能grow 到 256M *1001.
    但是存在gc调用,不知道gc会如何释放pool中的内存?
    把256M改为 1M的时候,发现内存会波动,没理解原因

golang case 语句

golang case 语句出现在三个地方

条件判断中的 switch...case

var a = "hello"
switch a {
case "hello":
    fmt.Println(1)
case "world":
    fmt.Println(2)
default:
    fmt.Println(0)
}

一分支多值

var a = "mum"
switch a {
case "mum", "daddy":
    fmt.Println("family")
}

分支表达式

var r int = 11
switch {
case r > 10 && r < 20:
    fmt.Println(r)
}

此时switch 没有变量和表达式,case 各分支默认和 true 比较
通过 fallthrough 继续执行其他case

var s = "hello"
switch {
case s == "hello":
    fmt.Println("hello")
    fallthrough
case s != "world":
    fmt.Println("world")
}

接口类型断言中的 switch...case

这种情况其实属于上种情况,只是和接口类型断言关联,比较常见,特拿出来单说

switch v := i.(type)  {
case int:
    ...
case string:
    ...
default:
    ...
}

关键字type只能用在switch语句里,如果用在switch外面会报错

并发模型中的 select...case

select {
case v1 := <-c1:
    fmt.Printf("received %v from c1\n", v1)
case v2 := <-c2:
    fmt.Printf("received %v from c2\n", v1)
case c3 <- 23:
    fmt.Printf("sent %v to c3\n", 23)
default:
    fmt.Printf("no one was ready to communicate\n")
}
  1. 除 default 外,如果只有一个 case 语句评估通过,那么就执行这个case里的语句;

  2. 除 default 外,如果有多个 case 语句评估通过,那么通过伪随机的方式随机选一个;

  3. 如果 default 外的 case 语句都没有通过评估,那么执行 default 里的语句;

  4. 如果没有 default,那么 代码块会被阻塞,指导有一个 case 通过评估;否则一直阻塞

实现 Sunday 匹配 needle在最末尾的时候返回结果异常

s := "hello world abc is a test chars in program develop comm"
index := strStrSunday(s, "common")
fmt.Println("common index is", index)
正常应该返回-1, 实际会返回54 什么的

附上根据原链接java 版本实现的一个方法:

`
func strStrSunday(haystack string, needle string) int {
if len(haystack) < len(needle) {
return -1
}

  if haystack == needle {
	  return 0
  }

  originIndex := 0
  aimIndex := 0
  nextIndex := 0

  for aimIndex < len(needle) {
	  if originIndex > len(haystack)-1 {
		  return -1
	  }

	  if haystack[originIndex] == needle[aimIndex] {
		  originIndex++
		  aimIndex++
	  } else {
		  nextIndex = originIndex - aimIndex + len(needle)
		  if nextIndex < len(haystack) {
			  offset := strings.LastIndex(needle, string(haystack[nextIndex]))
			  if offset == -1 {
				  originIndex = nextIndex + 1
			  } else {
				  originIndex = nextIndex - offset
			  }

			  aimIndex = 0
		  } else {
			  return -1
		  }
	  }
  }

  return originIndex - aimIndex

}
`

q014最后一题的解释不通啊

type Student struct {
Age int
}

func main() {
kv := map[string]*Student{"a":{Age:21}}
kv["a"].Age = 22
fmt.Println(kv)
}
这样修改为啥不报错了呢

实现 Sunday 匹配 精简版代码

https://github.com/lifei6671/interview-go/blob/master/algorithm/docs/match-sunday-string.md

精简版代码供参考:

func strStrSunday(haystack, needle string) int {
	if haystack == "" {
		return -1
	}
	if needle == "" {
		return 0
	}

	haystackLen := len(haystack)
	needleLen := len(needle)
	i := 0
	for {
		// 先判断剩余字符串的长度是否足够
		if i+needleLen > haystackLen {
			return -1
		}
		// 匹配上之后,直接返回index
		if haystack[i:i+needleLen] == needle {
			return i
		}
		// 判断needle所在位置的下一个占位是否包含在haystack中
		// needle所在位置的下一个占位可能超出haystack的长度
		if i+needleLen == haystackLen {
			return -1
		}
		//lastIdx := strings.LastIndex(needle, string(haystack[i+needleLen]))
		lastIdx := -1
		for j := needleLen - 1; j >= 0; j-- {
			if haystack[i+needleLen] == needle[j] {
				lastIdx = j
				break
			}
		}
		// 根据lastIdx结果进行不同的移位
		if lastIdx >= 0 {
			i += needleLen - lastIdx
		} else {
			i += needleLen + 1
		}
	}
}

冒泡排序完全是错的

冒泡排序是通过数去找位置,这里的冒泡排序写成选择排序了,附代码

func bubbleSort(arr []int) []int {
	if len(arr) == 0 {
		return arr
	}
	n := len(arr)
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-1-i; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	}
	return arr
}

q001.md

看到前面已经有一个关于这个问题的讨论,我还是选择了开了一个新的issue谈谈我的想法。


除了使用加锁的方法,还可以使用channel来实现goroutine调度,这是一个典型的 pingpong的问题,加上一个channel接受完成通知就好。


package main

import (
	"fmt"
)

func main() {
	ping := make(chan struct{}, 1)
	pong := make(chan struct{}, 1)
	done := make(chan struct{})

	ping <- struct{}{}
	go func() {
		for i := 0; i < 10; i++ {
			<-ping
			fmt.Print(i)
			pong <- struct{}{}
		}
	}()

	go func() {
		for i := 0; i < 10; i++ {
			<-pong
			fmt.Printf("%c", 'A'+i)
			ping <- struct{}{}
		}
		done <- struct{}{}
	}()

	<-done
	close(ping)
	close(pong)
}

最接近的三数之和,代码有误

`
func threeSumClosest(nums []int, target int) int {
if len(nums) == 3 {
return nums[0] + nums[1] + nums[2]
}
sort.Ints(nums)
sum := nums[0] + nums[1] + nums[2]

  for i := 0; i < len(nums); i++ {
	  l := i+1
	  r := len(nums) - 1
	  for l < r {
		  current := nums[i] + nums[l] + nums[r]
		  if math.Abs(float64(sum - target)) > math.Abs(float64(target - current)) {
			  sum = current
		  }
		  if current < target {
			  l++
		  } else if current == target {
			  return target
		  } else {
			  r--
		  }
	  }
  }
  return sum

}

`

『goroutine和channel使用一』 答案协程泄露

原题: https://github.com/lifei6671/interview-go/blob/master/question/q009.md
答案中done <- true 后面应该加上 return,否则子协程不会立刻退出, 往已经关闭的 done 写数据
如果此后做一些处理的话就会触发 panic

当函数被循环调用时, 必现 panic: send on closed channel

func main() {
	random := make(chan int)
	done := make(chan bool)

	go func() {
		for {
			num, ok := <-random
			if ok {
				fmt.Println(num)
			} else {
				done <- true
			}
		}
	}()

	go func() {
		defer close(random)

		for i := 0; i < 5; i++ {
			random <- rand.Intn(5)
		}
	}()

	<-done
	close(done)
        // 触发 panic
        time.Sleep(1 * time.Second)
}

实现阻塞读的并发安全Map

package main

import (
"fmt"
"time"
"sync"
)

type sp interface {
Out(key string, val interface{}) //存入key /val,如果该key读取的goroutine挂起,则唤醒。此方法不会阻塞,时刻都可以立即执行并返回
Rd(key string, timeout time.Duration) interface{} //读取一个key,如果key不存在阻塞,等待key存在或者超时
}

type Item2 struct {
value interface{}
ch chan struct{}
exist bool
}
type ConcurrentMap struct {
mapval map[string]*Item2
rwmutex *sync.RWMutex
}

func NewConcurrentMap() *ConcurrentMap {
return &ConcurrentMap{
mapval: make(map[string]*Item2, 0),
rwmutex: new(sync.RWMutex),
}
}

func (c *ConcurrentMap) Out(key string, val interface{}) {
c.rwmutex.Lock()
defer c.rwmutex.Unlock()

item, ok := c.mapval[key]
if !ok {
	c.mapval[key] = &Item2{
		value: val,
		exist: true,
	}
	return
}

item.value = val
if !item.exist {
	if item.ch != nil {
		close(item.ch)
		item.ch = nil
	}
}

return

}

func (c *ConcurrentMap) Rd(key string, timeout time.Duration) interface{} {
c.rwmutex.Lock()
defer c.rwmutex.Unlock()

item, ok := c.mapval[key]
if !ok {
	item = &Item2{
		exist: false,
		ch: make(chan struct{}, 1),
	}
	c.mapval[key] = item
}

if item.exist {
	return item.value
}

select {
case <-time.After(timeout):
	return nil
case <-item.ch:
}

item, _ = c.mapval[key]
return item.value

}

第七题的第七小题解答不够到位

https://github.com/lifei6671/interview-go/blob/master/question/q007.md#7%E4%B8%8B%E9%9D%A2%E7%9A%84%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E5%90%8E%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E7%88%86%E5%BC%82%E5%B8%B8

func (p *Project) run(msgchan chan interface{}) {
	for {
		defer p.deferError()
		go p.exec(msgchan)
		time.Sleep(time.Second * 2)
	}
}

这一段错误不仅是 defer p.deferError() 没有出现在协程内部,而是无节制地在创建协程。虽然通过 time.Sleep(time.Second * 2) 限制了频率,但如果以 Main 内 time.Sleep(time.Second * 100000000000000) 如此久的等待,迟早也会因为内存占用过大而报错。

建议多增加以下方面的内容

过往经验来看
企业面试gopher的时候
比较高频的问题
大体还是集中在
goroutine,channel,gRPC,gin方面
希望可以多增加这方面的内容

语法题目一 第11题,

第11题,是能正常执行完毕的,推测现在golang 的 GC 动作是不需要所有正在运行 goroutine 都停止后进行。猜测。

类似的题目不一样的答案

题目一
题目二
位于q007和q014的这两个题目问题是一样的,但是答案不一样,q007的答案更为准确,将题目二的代码改成这样就可以正确运行:

type Student struct {
	Age int
}
func main() {
	kv := map[string]*Student{"menglu": {Age: 21}}
	kv["menglu"].Age = 22
	s := []Student{{Age: 21}}
	s[0].Age = 22
	fmt.Println(kv, s)
}

我在stackoverflow上找到了和q007类似的解答:https://stackoverflow.com/a/32751792/4737579

翻转字符串

这个题目,不发生内存拷贝?? 讲道理, 字符串数组转换成[]rune切片, 就已经发生了内存拷贝了好吧

question17/多协程切片查询

有以下的两种情况,需要大家思考一下:
1、在规定的时间内,如果没找到,这种情况怎么处理,当前的处理方式是等到超时退出。
2、关于size的设定。需要根据具体情况跑benchmark,来确定最佳的性能。(同时也需要注意size太小的话,goroutine数量会太多)

第六题机器人坐标计算有问题

第六题机器人坐标计算
如果命令字符串包含嵌套的命令,那么题中的代码就会有问题。
举个例子,输入的命令为2(F3(B)),正确的答案是(0,-4)。然而给出的代码输出是(0,0)
正确的代码可以参考如下:

const (
	NORTH = iota
	EAST
	SOUTH
	WEST
)

type Offset struct {
	x int
	y int
}

var dirlist []Offset
var dirname []string

func init() {
	dirname = []string{"NORTH", "EAST", "SOUTH", "WEST"}
	dirlist = []Offset{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}
}

func getOffset(offset Offset, sign int, x int, y int) (int, int) {
	return x + offset.x*sign, y + offset.y*sign
}

func rmove(dir int, x int, y int, start int, s string) (int, int, int, int) {

	times := 0

	i := start
	//fmt.Printf("start:%d\n", start)
	for ; i < len(s); i++ {
		ch := s[i]
		//fmt.Printf("ch:%d,", ch)
		if ch >= '0' && ch <= '9' {
			times = times*10 + int(ch-'0')
		} else if ch == '(' {
			next := 0
			for j := 0; j < times; j++ {
				x, y, dir, next = rmove(dir, x, y, i+1, s)
			}
			i = next
		} else if ch == ')' {
			break
		} else if ch == 'R' {
			dir = (dir + 1) % 4
		} else if ch == 'L' {
			dir = (dir + 3) % 4

		} else if ch == 'F' {
			x, y = getOffset(dirlist[dir], 1, x, y)

		} else if ch == 'B' {
			x, y = getOffset(dirlist[dir], -1, x, y)
		}
	}
	//fmt.Printf("s:%s,x:%d,y:%d,dir:%d,i:%d\n", s, x, y, dir, i)
	return x, y, dir, i
}

// @返回参数1: 作标
// @返回参数2:方向
func move(s string) ([]int, int) {

	dir := NORTH
	x, y, dir, _ := rmove(dir, 0, 0, 0, s)
	//fmt.Printf("dir:%s\n", dirname[dir])
	return []int{x, y}, dir
}

一些建议

  1. 尽量给出使用标准库的解法,与纯算法(不使用任何库)两种。使用库将题做对,面试官可能也不会特别满意,虽然也足以应付一般的场景。
  2. 给出每个解法的时间复杂度,空间复杂度。如果能够分析为什么是这样最好。示例解法由于使用了大量标准库方法,效率太低了,除非你的代码永远没有优化的需求,否则你需要理解如何优化时间复杂度或空间复杂度。

q015 “双检查实现单例”问题

答案是:在多核CPU中,因为CPU缓存会导致多个核心中变量值不同步。
我的观点是:当前核心的变量值发生改变时,其他核心缓存中的值会置为不可用,当读取或修改时会重新从主存里读取。所以应该不会有不同步的问题。并且我也无法浮现这个问题 求解

翻转字符抖机灵版

func reverseString(s string) (string, bool) {
  str := []rune(s)
  l := len(str)
  if l > 5000 {
    return "", false
  }
  for i := 0 ; i < l/2; i++ {
    str[i] = str[l-i-1] - str[i]
	str[l-i-1] = str[l-i-1] - str[i]
	str[i] = str[i] + str[l-i-1]
  }
  return string(str), true
}

“实现阻塞读且并发安全的map”答案补充

我注意到https://github.com/lifei6671/interview-go/blob/master/question/q010.md中缺少了Rdfunc的实现,我完成了,并且经过了简单的测试。

func (m *Map) Rd(key string, timeout time.Duration) interface{} {
	e, ok := m.c[key]
	if !ok {
		// create channel
		m.c[key] = &entry{
			isExist: false,
			ch:      make(chan struct{}),
		}
	}
	// 阻塞
	e, _ = m.c[key]
	if e.ch != nil {
		select {
		case <-e.ch:
		case <-time.After(timeout):
		}
	}
	return m.c[key].value
}

q007常见语法题 第8题

func main() {
	abc := make(chan int, 1000)
	for i := 0; i < 10; i++ {
		abc <- i
	}
	go func() {
		for {
			a := <-abc
			fmt.Println("a: ", a)
		}
	}()
	close(abc)
	fmt.Println("close")
	time.Sleep(time.Second * 100)
}

这个最大的问题是没有做channel读取的检查吧 ,loop循环的时候如果不检查是否channel可读,会一直输出类型的初始化值(0) 上面的代码会打印大量无用的0值, 只要检查后退出即可

func main() {
	abc := make(chan int, 1000)
	for i := 0; i < 10; i++ {
		abc <- i
	}
	go func() {
		for {
			a, ok  := <-abc
			if ok{
				fmt.Println("a: ", a)
			}else{
				return
			}

		}
	}()
	close(abc)
	fmt.Println("close")
	time.Sleep(time.Second * 100)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.