用Go并发来解决leetcode的几道并发编程题

一、leetcode 1114 

1114. 按序打印

import (
	"fmt"
)

func printFirst(notifySecond chan int) {
	fmt.Println("first")
	close(notifySecond)
}
func printSecond(notifySecond chan int, notifyThird chan int) {
	select {
	case <-notifySecond:
		fmt.Println("second")
	}

	close(notifyThird)

}

func printThird(notifyThird chan int) {
	select {
	case <-notifyThird:
		fmt.Println("third")
	}

}

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go printThird(ch2)
	go printFirst(ch1)
	//go printThird(ch2)
	go printSecond(ch1, ch2)

	for {

	}

}

 我们通过两个channel来互相通知,要求必须执行 打印first-通知打印second-打印second-通知打印third。

二、交替打印foo bar

1115. 交替打印 FooBar


func printFoo(myCh, otherCh chan int) {
	for {
		select {
		case <-myCh:
			fmt.Println("foo")
			time.Sleep(1 * time.Second)
			otherCh <- 1
		}
	}
}
func printBar(myCh, otherCh chan int) {
	for {
		select {
		case <-myCh:
			fmt.Println("bar")
			time.Sleep(1 * time.Second)
			otherCh <- 1
		}
	}
}

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go printFoo(ch1, ch2)
	go printBar(ch2, ch1)

	ch1 <- 1//start all

	for {
	}
}

我们思考为了让他们交替打印,需要两个goroutinue之间有双向通信的装置,ch1代表发送给foo函数,触发它的打印;ch2代表发送给bar函数,触发它的打印。打印结束后,需要向另一个channel发送消息,通知另一个goroutinue,这就成了一个轮流通知对方的过程。不过需要注意的是,刚开始channel里面没有任何数据,需要手动触发它的第一次打印(这里如果先发给ch1那就是先打印foo)

三、打印零和奇偶数

1116. 打印零与奇偶数

 分析一下其实并不难,简单来说每次通知到底是odd协程打印还是even协程打印由zero协程控制,但是odd和even协程一旦执行完毕必须通知zero。

ps:这里其实就体现出线程间协同并发的基本原理就是“通知”,无论要求做出什么样的协同场景,都要先分析线程间的通知流程。

var globalCnt int = 0
var maxN int = 0
var zeroChan = make(chan int)
var oddChan = make(chan int)
var evenChan = make(chan int)

func printNumber(n int) {
	fmt.Printf("%d", n)
}

func zero() {
	for {
		select {
		case <-zeroChan:
			if globalCnt >= maxN {
				return
			}
			printNumber(0)
			time.Sleep(1 * time.Second)
			if globalCnt%2 == 1 {
				oddChan <- 1
			} else {
				evenChan <- 1
			}

		}
	}
}

func odd() {
	for {
		select {
		case <-oddChan:
			globalCnt++
			printNumber(globalCnt)

			time.Sleep(1 * time.Second)
			zeroChan <- 1

		}
	}
}

func even() {
	for {
		select {
		case <-evenChan:
			globalCnt++
			printNumber(globalCnt)

			time.Sleep(1 * time.Second)
			zeroChan <- 1
		}
	}
}

func main() {
	maxN = 3
	go zero()
	go even()
	go odd()
	zeroChan <- 1

	for {
	}

}

 

四、H2O生成

1117. H2O 生成

这个题要求使用两线程要求生产的一定是一组[H,H,O]字符,为了验证最终正确性,我们将随机启动m个H线程(协程)和n个O线程(协程),打印应当是3的倍数而且每组都是2个H一个O。

分析通知流程可知,O协程应当一次性通知2个H协程,而且H协程对O协程的通知,应当收到2个信号才能符合要求。

var hCh = make(chan int, 2)
var oCh = make(chan int, 2)
var cnt = &Counter{0}

type Counter struct {
	cnt int32
}

func (c *Counter) Increase() {
	atomic.AddInt32(&c.cnt, 1)
}
func (c *Counter) GetValue() int32 {
	return c.cnt
}

func hydrogen() {
	select {
	case <-hCh:
		fmt.Printf("H")
		oCh <- 1
	}
}

func oxygen() {
	select {
	case <-oCh:

		if cnt.GetValue()%2 == 0 {
			fmt.Printf("O")
			hCh <- 1
			hCh <- 2
		}
		cnt.Increase()

	}
}

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {

	for i := 0; i < 30; i++ {
		t := rand.Intn(197) % 3
		if t == 0 {
			//fmt.Println("start oxygen")
			go oxygen()
		} else {
			//fmt.Println("start hydrogen")
			go hydrogen()
		}
	}

	oCh <- 1

	for {

	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值