算法唯手熟尔4月(PAT剩余清单 or leetcode)---希望可以日更

文章目录


hexo链接: link

2020/4/1

leetcode 914. 卡牌分组_Go
package main

import (
	"fmt"
)

func gcd(a, b int) int {
	if b == 0 {
		return a
	}
	return gcd(b, a%b)
}

func hasGroupsSizeX(deck []int) bool {
	m := make(map[int]int)
	for i := 0; i < len(deck); i++ {
		m[deck[i]]++
	}
	for _, value := range m {
		for _, k := range m {
			if gcd(value, k) < 2 {
				return false
			}
		}
	}
	return true
}

// 感觉就是一个Hash,再加上gcd
func main() {
	deck := []int{1, 1, 1, 1, 2, 2, 2, 2, 2, 2}
	fmt.Println(hasGroupsSizeX(deck))
}

leetcode 1111. 有效括号的嵌套深度_Go
package main

import "fmt"

func maxDepthAfterSplit(seq string) []int {
	stack := make([]int, 0, len(seq))
	var deep = -1
	for _, v := range seq {
		if string(v) == "(" {
			deep++
			stack = append(stack, deep%2)
		}
		if string(v) == ")" {
			stack = append(stack, deep%2)
			deep--
		}
	}
	return stack
}

// 说实话,这题目我都看了半天
// depth("(" + A + ")") = 1 + depth(A) 关键是这句话理解就好了
// 分析到最后就是把左括号竟可能的分成两个序列即可
func main() {
	seq := "(()())"
	ans := maxDepthAfterSplit(seq)
	fmt.Println(ans)
}

2020/4/2

leetcode 289. 生命游戏_Go
package main

import (
	"fmt"
)

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func gameOfLife(board [][]int) {
	way := [3]int{0, 1, -1}
	row := len(board)
	col := len(board[0])
	// select every node
	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			aliveNum := 0
			// select each direction
			// 和迷宫走法一样
			for x := 0; x < 3; x++ {
				for y := 0; y < 3; y++ {
					if way[x] != 0 || way[y] != 0 {
						r := way[x] + i
						c := way[y] + j
						// check border
						if (r >= 0 && r < row) && (c >= 0 && c < col) {
							if abs(board[r][c]) == 1 {
								aliveNum++
								fmt.Println(aliveNum, i, j)
							}
						}
					}
				}
			}
			// check status
			// alive ->dead
			if (board[i][j] == 1) && (aliveNum < 2 || aliveNum > 3) {
				board[i][j] = -1
			}
			// dead ->alive
			if (board[i][j] == 0) && (aliveNum == 3) {
				board[i][j] = 2
			}
		}
	}
	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			if board[i][j] > 0 {
				board[i][j] = 1
			} else {
				board[i][j] = 0
			}
		}
	}
}

// 生命游戏,第一眼觉得是个图题,后来才知道主要是为了练符合状态
// 需要变化的是结点本身的状态,改变依据是周围结点的状态
// 硬做的话提前备份一个二维数组就好,尝试一下原地算法
// 原地算法不依赖额外的资源或者依赖少数的额外资源,仅依靠输出来覆盖输入的一种算法操作。
// 需要对改变后的数组状态做一些新的标记,来避免与0/1状态混淆
/*
alive->dead :-1
alive->alive :1
dead->alive :2
*/
func main() {
	var board = make([][]int, 0)
	temp := []int{0, 1, 0}
	board = append(board, temp)
	temp = []int{0, 0, 1}
	board = append(board, temp)
	temp = []int{1, 1, 1}
	board = append(board, temp)
	temp = []int{0, 0, 0}
	board = append(board, temp)
	fmt.Println(board)
	gameOfLife(board)
	fmt.Println(board)
}

2020/4/3

leetcode 8. 字符串转换整数_Go
package main

import (
	"fmt"
	"math"
	"strings"
	"unicode"
)

// 自动机什么的是学不会的,但各种情况的逻辑判断需要好好锻炼
func myAtoi(str string) int {
	flag := 1
	// 按找空白符分割字符串成一个切片
	strSlice := strings.FieldsFunc(str, unicode.IsSpace)
	//fmt.Println(strSlice, reflect.TypeOf(strSlice))
	// 分割后只需要判断切片内第一个元素即可
	var temp string
	// 防止输入""
	if len(strSlice) == 0 {
		return 0
	}
	if !unicode.IsDigit(rune(strSlice[0][0])) {
		if strSlice[0][0] == '+' {
			flag = 1
			strSlice[0] = strSlice[0][1:]
			//fmt.Println(strSlice[0])
		} else if strSlice[0][0] == '-' {
			flag = -1
			strSlice[0] = strSlice[0][1:]
		} else {
			return 0
		}
	}
	first := strSlice[0]
	for i := 0; i < len(first); i++ {
		if !unicode.IsDigit(rune(first[i])) {
			break
		} else {
			temp += string(first[i])
		}
	}
	// strToNum
	ans := 0
	for i := 0; i < len(temp); i++ {
		ans = int(temp[i]-'0') + ans*10
		if ans*flag > math.MaxInt32 {
			return math.MaxInt32
		}
		if ans*flag < math.MinInt32 {
			return math.MinInt32
		}
	}
	return flag * ans
}

func main() {
	//str := "-996 9k3 and 987"
	//str2 := "words and 987"
	str3 := "-91283472332"
	fmt.Println(myAtoi(str3))
}

2020/4/4

leetcode 42. 接雨水_Go
package main

import "fmt"

// 暴力思维:两边最大高度的较小值减去当前高度的值
// 但暴力不可取,还是不暴力了……
// 题解里那个栈的应用是真的没想到,tcl
// 用two pointers来解决
func trap(height []int) int {
	left := 0
	right := len(height) - 1
	ans := 0
	leftMax, rightMax := 0, 0
	for left < right {
		if height[left] < height[right] {
			if height[left] >= leftMax {
				leftMax = height[left]
			} else {
				ans += leftMax - height[left]
			}
			left++
		} else {
			if height[right] >= rightMax {
				rightMax = height[right]
			} else {
				ans += rightMax - height[right]
			}
			right--
		}
	}
	return ans
}

func main() {
	height := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}
	fmt.Println(trap(height))
}

2020/4/5

leetcode 460. LFU缓存_Go

真难……

package main

import "fmt"

// Node struct
type Node struct {
	key, value int
	num        int   // 调用次数
	prev, next *Node // 前序,后继指针,为双重链表做准备
}

// DoubleList prepare for freeList
type DoubleList struct {
	head, tail *Node
}

// ConstructorDB init
func ConstructorDB() *DoubleList {
	head, tail := &Node{}, &Node{}
	head.next, tail.prev = tail, head
	return &DoubleList{
		head: head,
		tail: tail,
	}
}

// LFUCache struct
type LFUCache struct {
	capacity int
	rest     int // 剩余容量
	minFreq  int // 当前最少num
	cache    map[int]*Node
	freqList map[int]*DoubleList // key是调用的num,每个建对应的值是一个链表,越靠近头结点调用的越近
}

// Constructor init
func Constructor(capacity int) LFUCache {
	return LFUCache{
		capacity: capacity,
		rest:     capacity,
		cache:    make(map[int]*Node),
		freqList: make(map[int]*DoubleList),
		minFreq:  0,
	}
}

// Remove node from DoubleList
func (p *DoubleList) Remove(node *Node) {
	node.prev.next = node.next
	node.next.prev = node.prev
	node.next = nil
	node.prev = nil
}

// IsEmpty -> Judge if DoubleList is empty
func (p *DoubleList) IsEmpty() bool {
	return p.head.next == p.tail
}

// AddNode -> add node to doubleList
func (p *DoubleList) AddNode(node *Node) {
	node.next = p.head.next
	node.prev = p.head
	p.head.next.prev = node
	p.head.next = node
}

// UpdateFre freeList
func (p *LFUCache) UpdateFre(node *Node) {
	freq := node.num
	p.freqList[freq].Remove(node)
	// Judge if its num is min
	if p.minFreq == freq && p.freqList[freq].IsEmpty() {
		p.minFreq++
		delete(p.freqList, freq)
	}
	node.num++
	if p.freqList[node.num] == nil {
		p.freqList[node.num] = ConstructorDB()
	}
	p.freqList[node.num].AddNode(node)
}

// Get output
func (p *LFUCache) Get(key int) int {
	node, ok := p.cache[key]
	if ok {
		p.UpdateFre(node)
		return node.value
	}
	return -1
}

// RemoveLast -> remove last node
func (p *DoubleList) RemoveLast() *Node {
	if p.IsEmpty() {
		return nil
	}
	last := p.tail.prev
	p.Remove(last)
	return last
}

// Put input
func (p *LFUCache) Put(key int, value int) {
	if p.capacity == 0 {
		return
	}
	node, ok := p.cache[key]
	if ok {
		node.value = value
		p.UpdateFre(node)
	} else {
		if p.rest == 0 {
			node := p.freqList[p.minFreq].RemoveLast()
			delete(p.cache, node.key)
			p.rest++
		}
		temp := &Node{key: key, value: value, num: 1}
		p.cache[key] = temp
		if p.freqList[1] == nil {
			p.freqList[1] = ConstructorDB()
		}
		p.freqList[1].AddNode(temp)
		p.minFreq = 1
		p.rest--
	}
}

func main() {
	cache := Constructor(2)
	cache.Put(1, 1)
	cache.Put(2, 2)
	fmt.Println(cache.Get(1)) // 返回 1
	cache.Put(3, 3)           // 去除 key 2
	fmt.Println(cache.Get(2)) // 返回 -1 (未找到key 2)
	fmt.Println(cache.Get(3)) // 返回 3
	cache.Put(4, 4)           // 去除 key 1
	fmt.Println(cache.Get(1)) // 返回 -1 (未找到 key 1)
	fmt.Println(cache.Get(3)) // 返回 3
	fmt.Println(cache.Get(4)) // 返回 4
}

2020/4/6

今天的每日一题我直接放弃了,做之前简单的吧……

leetcode 1013. 将数组分成相等的三个部分_Go
package main

import "fmt"

func canThreePartsEqualSum(A []int) bool {
	sum := 0
	for i := 0; i < len(A); i++ {
		sum += A[i]
	}
	if sum%3 != 0 {
		return false
	}
	target := sum / 3
	idx, sumTemp := 0, 0
	for idx < len(A) {
		sumTemp += A[idx]
		if sumTemp == target {
			break
		}
		idx++
	}
	if sumTemp != target {
		return false
	}
	idx++
	for idx+1 < len(A) { // 满足最后一部分非空
		sumTemp += A[idx]
		if sumTemp == 2*target {
			return true
		}
		idx++
	}
	return false
}

func main() {
	A := []int{0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1}
	fmt.Println(canThreePartsEqualSum(A))
}

2020/4/7

leetcode 面试题 01.07. 旋转矩阵_Go

我自己本身没有去纠结原地算法,我觉得这一题让我进一步了解copy这个机制已经有收获了

package main

import "fmt"

func rotate(matrix [][]int) {
	length := len(matrix)
	ans := make([][]int, length)
	for i := 0; i < length; i++ {
		ans[i] = make([]int, length)
	}
	for i := 0; i < length; i++ {
		for j := 0; j < length; j++ {
			ans[j][length-i-1] = matrix[i][j]
		}
	}
	copy(matrix, ans)
}

func main() {
	matrix := [][]int{
		{1, 2, 3},
		{4, 5, 6},
		{7, 8, 9},
	}
	rotate(matrix)
	fmt.Println(matrix)
}

2020/4/8

leetcode 面试题13. 机器人的运动范围_Go
package main

import "fmt"

func addNum(a int) int {
	ans := 0
	for a > 0 {
		ans += a % 10
		a /= 10
	}
	return ans
}

func judge(row, col, m, n, k int, visit [][]int) bool {
	if row < 0 || row >= m {
		return false
	}
	if col < 0 || col >= n {
		return false
	}
	if visit[row][col] == 1 {
		return false
	}
	visit[row][col] = 1
	ans := addNum(row) + addNum(col)
	return ans <= k
}

func movingCount(m int, n int, k int) int {
	visit := make([][]int, m)
	for i := 0; i < m; i++ {
		visit[i] = make([]int, n)
	}
	num := 0
	// init queue
	queue := [][]int{}
	temp := []int{0, 0}
	queue = append(queue, temp)
	visit[0][0] = 1
	// BFS
	for len(queue) != 0 {
		top := queue[0]
		queue = queue[1:]
		num++
		if judge(top[0]-1, top[1], m, n, k, visit) {
			temp = []int{top[0] - 1, top[1]}
			queue = append(queue, temp)
		}
		if judge(top[0]+1, top[1], m, n, k, visit) {
			temp = []int{top[0] + 1, top[1]}
			queue = append(queue, temp)
		}
		if judge(top[0], top[1]-1, m, n, k, visit) {
			temp = []int{top[0], top[1] - 1}
			queue = append(queue, temp)
		}
		if judge(top[0], top[1]+1, m, n, k, visit) {
			temp = []int{top[0], top[1] + 1}
			queue = append(queue, temp)
		}
	}
	return num
}

func main() {
	fmt.Println(movingCount(2, 3, 1))
}

2020/4/9

leetcode 22. 括号生成_Go

这题我是用暴力做的

但引出了切片作为函数参数这个大坑,资料:https://www.jianshu.com/p/7439e7ae3c4c

从输出可以看出,当slice传递给函数的时候,新建了切片s。在函数中给s进行了append一个元素,由于此时s的容量足够到,并没有生成新的底层数组。当修改返回的ret的时候,ret也共用了底层的数组,因此修改ret的原始,相应的也看到了slice的改变。

append 操作

如果在函数内,append操作超过了原始切片的容量,将会有一个新建底层数组的过程,那么此时再修改函数返回切片,应该不会再影响原始切片

也就是说不在共享一个底层数组,那么即使是全局变量也无法修改了,大坑!!!

package main

import "fmt"

// 先用暴力算法写
// 要是这题的思路弄清楚,我觉得递归就入门了,学习一下

func generateParenthesis(n int) []string {
	var current string
	var result = []string{}
	generateAll(&current, n*2, &result)
	//fmt.Println(result)
	return result
}

func generateAll(current *string, n int, result *[]string) {
	if n == len(*current) {
		if valid(*current) {
			*result = append(*result, *current)
			//fmt.Println(result)
		}
		return
	}
	*current += "("
	generateAll(current, n, result)
	*current = (*current)[:len(*current)-1]
	*current += ")"
	generateAll(current, n, result)
	*current = (*current)[:len(*current)-1]
}

func valid(str string) bool {
	balance := 0
	for i := 0; i < len(str); i++ {
		if string(str[i]) == "(" {
			balance++
		} else {
			balance--
			if balance < 0 {
				return false
			}
		}
	}
	return balance == 0
}

func main() {
	ans := generateParenthesis(3)
	fmt.Println(ans)
}


package main

import "fmt"

// 回溯法
func generateParenthesis(n int) []string {
	var current string
	var result = []string{}
	generateAll(&current, n, &result, 0, 0)
	//fmt.Println(result)
	return result
}

func generateAll(current *string, n int, result *[]string, open int, close int) {
	if len(*current) == 2*n {
		*result = append(*result, *current)
		return
	}
	if open < n {
		*current += "("
		generateAll(current, n, result, open+1, close)
		*current = (*current)[:len(*current)-1]
	}
	if close < open {
		*current += ")"
		generateAll(current, n, result, open, close+1)
		*current = (*current)[:len(*current)-1]
	}
}

func main() {
	ans := generateParenthesis(3)
	fmt.Println(ans)
}

用了回溯时间快了两倍,剪枝还是重要的

2020/4/10

leetcode 151.翻转字符串里的单词_Go

这题用相关api做起来是很快的,既然可以直接写,用双端队列我觉得就有点得不偿失了,毕竟go中要用stack需要自己写

package main

import (
	"fmt"
	"strings"
	"unicode"
)

func reverseWords(s string) string {
	var ans string
	slice := strings.FieldsFunc(s, unicode.IsSpace)
	for i := len(slice) - 1; i >= 0; i-- {
		ans += slice[i]
		if i > 0 {
			ans += " "
		}
	}
	return ans
}

func main() {
	ans := "the sky is blue"
	fmt.Println(reverseWords(ans))
}

leetcode 面试题 01.06. 字符串压缩_Go
package main

import (
	"fmt"
	"strconv"
)

// 掌握到了一个int转换成string的函数
func compressString(S string) string {
	if len(S) == 0 {
		return ""
	}
	var ans string
	temp := S[0]
	count := 0
	for i := 0; i < len(S); i++ {
		if S[i] != temp {
			ans += (string(temp) + strconv.Itoa(count))
			temp = S[i]
			count = 1
		} else {
			count++
		}
	}
	ans += (string(temp) + strconv.Itoa(count))
	if len(ans) >= len(S) {
		ans = S
	}
	return ans
}

func main() {
	ans := "aabcccccaaa"
	fmt.Println(compressString(ans))
}

2020/4/11

leetcode 887.鸡蛋掉落_Go

说实话有点懵,就当学习dp了,之前看过dp,但也不至于这么难想公式

首先,第一步,直接阅读题解

第二步,解法一有二分,哦,想法一样

第三步,嗯?咋是这么写的,那没事了,我不会

这个视频讲的蛮好的:https://www.bilibili.com/video/BV1CJ411s7ud?from=search&seid=18159411945702423360

毕竟就算了解了dp怎么推到代码这个阶段水平要求还是高的

只用了DP的思路,超时的答案如下,还是很清晰易懂的

package main

import (
	"fmt"
	"math"
)

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func superEggDrop(K int, N int) int {
	// init dp array
	DP := [101][10001]int{}
	for i := 0; i <= K; i++ {
		for j := 0; j <= N; j++ {
			DP[i][j] = math.MaxInt32
		}
	}
	for i := 0; i <= N; i++ {
		DP[0][i] = 0
		DP[1][i] = i
	}
	for i := 0; i <= K; i++ {
		DP[i][0] = 0
	}
	for k := 2; k <= K; k++ {
		for n := 1; n <= N; n++ {
			for i := 1; i <= n; i++ {
				DP[k][n] = min(DP[k][n], max(DP[k-1][i-1], DP[k][n-i])+1)
			}
		}
	}
	return DP[K][N]
}

func main() {
	fmt.Println(superEggDrop(3, 14))
}


尝试一下优化

这里用到了题解中的单调性,真厉害啊,在第五层

package main

import (
	"fmt"
	"math"
)

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func superEggDrop(K int, N int) int {
	// init dp array
	DP := [101][10001]int{}
	for i := 0; i <= K; i++ {
		for j := 0; j <= N; j++ {
			DP[i][j] = math.MaxInt32
		}
	}
	for i := 0; i <= N; i++ {
		DP[0][i] = 0
		DP[1][i] = i
	}
	for i := 0; i <= K; i++ {
		DP[i][0] = 0
	}
	for k := 2; k <= K; k++ {
		for n := 1; n <= N; n++ {
			// for i := 1; i <= n; i++ {
			// 	DP[k][n] = min(DP[k][n], max(DP[k-1][i-1], DP[k][n-i])+1)
			// }
			// 二分搜索
			low, high := 1, n
			m := 0
			for low <= high {
				m = (high-low)/2 + low
				x, y := DP[k-1][m-1], DP[k][n-m]
				if x > y {
					high = m - 1
				} else {
					low = m + 1
				}
				DP[k][n] = min(DP[k][n], max(x, y)+1)
			}
		}
	}
	return DP[K][N]
}

func main() {
	fmt.Println(superEggDrop(3, 14))
}

终于搞定了,对dp的理解又加深了

2020/4/12

leetcode 面试题 16.03. 交点_Go

因为精度问题失败了

package main

import (
	"fmt"
	"math"
)

// 这题完全不会,几何学一般性的面试也不会考吧,图像和游戏?
// 单纯因为好奇怎么做才看着题解学习了一下,这题其实感觉没什么必要
// 然后看到一堆数学直接放弃
// 只能用分类讨论了,还好昨天练了一下dp,今天用上了,怀疑官方就是这么考虑才出的题
func intersection(start1 []int, end1 []int, start2 []int, end2 []int) []float64 {
	if start1[0] > end1[0] {
		start1, end1 = end1, start1
	}
	if start2[0] > end2[0] {
		start2, end2 = end2, start2
	}
	// 两条垂直线
	if start1[0] == end1[0] && start2[0] == end2[0] {
		if start1[1] > end1[1] {
			start1, end1 = end1, start1
		}
		if start2[1] > end2[1] {
			start2, end2 = end2, start2
		}
		ans := twoVertical(start1, end1, start2, end2)
		return ans
	} else if start1[0] == end1[0] { // 一条垂线
		if start1[1] > end1[1] {
			start1, end1 = end1, start1
		}
		return oneVertical(start1, end1, start2, end2)
	} else if start2[0] == end2[0] {
		if start2[1] > end2[1] {
			start2, end2 = end2, start2
		}
		return oneVertical(start2, end2, start1, end1)
	}
	// 无垂直线
	return noVertical(start1, end1, start2, end2)
}

func twoVertical(start1 []int, end1 []int, start2 []int, end2 []int) []float64 {
	ans := []float64{}
	if start1[0] != start2[0] {
		return ans
	}
	low, high := math.Max(float64(start1[1]), float64(start2[1])), math.Min(float64(end1[1]), float64(end2[1]))
	if low <= high {
		ans = []float64{float64(start1[0]), low}
		return ans
	}
	return ans
}

func oneVertical(start1 []int, end1 []int, start2 []int, end2 []int) []float64 {
	ans := []float64{}
	if start1[0] < start2[0] || start1[0] > end2[0] {
		return ans
	}
	y := calY(start2, end2, start1[0])
	if y >= start1[1] && y <= end1[1] {
		ans = []float64{float64(start1[0]), float64(y)}
		return ans
	}
	return ans
}

func noVertical(start1 []int, end1 []int, start2 []int, end2 []int) []float64 {
	ans := []float64{}
	interX1, interX2 := math.Max(float64(start1[0]), float64(start2[0])), math.Min(float64(end1[0]), float64(end2[0]))
	if interX1 > interX2 {
		return ans
	}
	left, right := interX1, interX2
	interY1Left := calY(start1, end1, int(left))
	interY2Left := calY(start2, end2, int(left))
	interY1Right := calY(start1, end1, int(right))
	interY2Right := calY(start2, end2, int(right))
	if interY1Left == interY2Left {
		ans = []float64{left, float64(interY1Left)}
		return ans
	}
	if interY1Right == interY2Right {
		ans = []float64{right, float64(interY2Right)}
		return ans
	}
	if (interY1Left-interY2Left)*(interY1Right-interY2Right) > 0 {
		return ans
	}

	// 二分,精度为给定的10^(-6)
	sign := -1
	if interY1Left > interY2Left {
		sign = 1
	}
	for right-left > math.Pow10(-6) {
		mid := (int(right) + int(left)) / 2
		y1 := calY(start1, end1, mid)
		y2 := calY(start2, end2, mid)
		if y1 == y2 {
			ans = []float64{float64(mid), float64(y1)}
			return ans
		}
		if (y1-y2)*sign > 0 {
			left = float64(mid)
		}
		right = float64(mid)
	}
	ans = []float64{left, right}
	return ans
}

func calY(start []int, end []int, x int) int {
	slope := (end[1] - start[1]) / (end[0] - start[0])
	return slope*(x-start[0]) + start[1]
}

func main() {
	start1, end1 := []int{0, 0}, []int{1, 0}
	start2, end2 := []int{1, 1}, []int{0, -1}
	fmt.Println(intersection(start1, end1, start2, end2))
}


用数学的做法做,我反正是学不来的,挂个答案记录一下,也没提交反正,慢慢学习

func intersection(start1 []int, end1 []int, start2 []int, end2 []int) []float64 {
    const eps = 1e-6
    sub := func(a, b []int) []int {
        c := make([]int, 2)
        c[0] = a[0] - b[0]
        c[1] = a[1] - b[1]
        return c
    }
    det := func(a, b []int) int { // 行列式或叉积
        return a[0]*b[1]-a[1]*b[0]
    }
    inline := func(s, v, p []int) bool { // 检测p是否在线段 p=s+vt 上 (0<=t<=1)
        i := 0
        if v[i]==0 { i = 1 }
        t := float64((p[i]-s[i])) / float64(v[i])
        if -eps <= t && t <= 1+eps { return true }
        return false
    }
    v1 := sub(end1, start1)
    v2 := sub(end2, start2)
    b := sub(start2, start1)
    denominator := det(v1, v2)
    ans := []float64{}
    if denominator == 0 { // 平行
        if det(v1, b) == 0 { // 共线
            tmp := [][]int{start1, end1, start2, end2}
            // 排序后第二个点为候选点
            sort.Slice(tmp, func(i, j int) bool {
                if tmp[i][0] < tmp[j][0] {
                    return true
                } else if tmp[i][0]==tmp[j][0] && tmp[i][1]<tmp[j][1] {
                    return true
                }
                return false
            })
            // 检测是否同时在两线段上
            if inline(start1, v1, tmp[1]) && inline(start2, v2, tmp[1]) {
                ans = []float64{float64(tmp[1][0]), float64(tmp[1][1])}
            }
        }
    } else { // 直线相交
        t1 := float64(det(b, v2)) / float64(denominator) // p=s1+v1*t1 (0<=t1<=1)
        t2 := -float64(det(v1, b)) / float64(denominator)
        if 0<=t1&&t1<=1 && 0<=t2&&t2<=1 { // 交点是否在线段上
            ans = []float64{float64(start1[0])+float64(v1[0])*t1, 
                        float64(start1[1])+float64(v1[1])*t1}
        }
    }
    return ans
}

2020/4/14

leetcode 455. 两数相加Ⅱ_Go
package main

import (
	"container/list"
	"fmt"
)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

// ListNode struct
type ListNode struct {
	Val  int
	Next *ListNode
}

// 逆序处理要想到栈,关键就是这点
// 之前看了container/list的库,立刻就派上用处了
// 这个我是直接模改的算法笔记上面C++的模板
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	stack1 := list.New()
	stack2 := list.New()
	for l1 != nil {
		stack1.PushFront(l1.Val)
		l1 = l1.Next
	}
	for l2 != nil {
		stack2.PushFront(l2.Val)
		l2 = l2.Next
	}
	p := l1
	carry := 0
	for stack1.Len() > 0 && stack2.Len() > 0 {
		val := stack1.Front().Value.(int) + stack2.Front().Value.(int) + carry
		carry = 0
		if val > 9 {
			val -= 10
			carry = 1
		}
		node := &ListNode{
			Val:  val,
			Next: p,
		}
		p = node
		stack1.Remove(stack1.Front())
		stack2.Remove(stack2.Front())
	}
	for stack1.Len() > 0 {
		val := stack1.Front().Value.(int) + carry
		carry = 0
		if val > 9 {
			val -= 10
			carry = 1
		}
		node := &ListNode{
			Val:  val,
			Next: p,
		}
		p = node
		stack1.Remove(stack1.Front())
	}
	for stack2.Len() > 0 {
		val := stack2.Front().Value.(int) + carry
		carry = 0
		if val > 9 {
			val -= 10
			carry = 1
		}
		node := &ListNode{
			Val:  val,
			Next: p,
		}
		p = node
		stack2.Remove(stack2.Front())
	}
	if carry > 0 {
		node := &ListNode{
			Val:  carry,
			Next: p,
		}
		p = node
	}
	return p
}

func main() {
	l1 := &ListNode{7, nil}
	l1.Next = new(ListNode)
	l1.Next = &ListNode{2, nil}
	l1.Next.Next = new(ListNode)
	l1.Next.Next = &ListNode{4, nil}
	l1.Next.Next.Next = new(ListNode)
	l1.Next.Next.Next = &ListNode{3, nil}

	l2 := &ListNode{5, nil}
	l2.Next = new(ListNode)
	l2.Next = &ListNode{6, nil}
	l2.Next.Next = new(ListNode)
	l2.Next.Next = &ListNode{4, nil}

	ans := addTwoNumbers(l1, l2)
	for ans != nil {
		fmt.Println(ans.Val, "->")
		ans = ans.Next
	}
	fmt.Println("nil")
}

leetcode 53. 最大字序和_Go
package main

import "fmt"

// basic dp
func maxSubArray(nums []int) int {
	length := len(nums)
	dp := make([]int, length+1)
	ans := nums[0]
	for i := 1; i < length+1; i++ {
		dp[i] = max(dp[i-1]+nums[i-1], nums[i-1])
		if ans < dp[i] {
			ans = dp[i]
		}
	}
	return ans
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	nums := []int{-1}
	fmt.Println(maxSubArray(nums))
}

2020/4/15

leetcode 542. 01矩阵_Go
package main

import "fmt"

// BFS
func updateMatrix(matrix [][]int) [][]int {
	wayx := [4]int{0, 0, 1, -1}
	wayy := [4]int{1, -1, 0, 0}
	queue := [][]int{}
	row := len(matrix)
	col := len(matrix[0])
	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			if matrix[i][j] == 0 {
				queue = append(queue, []int{i, j})
			} else {
				// 未访问过的1设置为-1
				matrix[i][j] = -1
			}
		}
	}
	for len(queue) != 0 {
		top := queue[0]
		queue = queue[1:]
		x, y := top[0], top[1]
		for i := 0; i < 4; i++ {
			newX := x + wayx[i]
			newY := y + wayy[i]
			if newX >= 0 && newX < row && newY >= 0 && newY < col && matrix[newX][newY] == -1 {
				matrix[newX][newY] = matrix[x][y] + 1
				queue = append(queue, []int{newX, newY})
			}
		}
	}
	return matrix
}

func main() {
	matrix := [][]int{{0, 0, 0},
		{0, 1, 0},
		{0, 0, 0}}
	fmt.Println(updateMatrix(matrix))
}

2020/4/16

leetcode 52. 合并区间_Go
package main

import (
	"fmt"
	"sort"
)

func merge(intervals [][]int) [][]int {
	if len(intervals) <= 0 {
		return nil
	}
	// 利用匿名函数排序
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i][0] < intervals[j][0]
	})
	ans := [][]int{}
	ans = append(ans, intervals[0])
	for i := 1; i < len(intervals); i++ {
		right := ans[len(ans)-1]
		temp := intervals[i]
		if temp[0] > right[1] {
			ans = append(ans, temp)
			continue
		} else {
			if temp[1] > right[1] {
				right[1] = temp[1]
			}
		}
	}
	return ans
}

func main() {
	intervals := [][]int{{1, 3}, {2, 6}, {8, 10}, {15, 18}}
	fmt.Println(merge(intervals))
}

2020/4/17

leetcode 55. 跳跃游戏_Go
package main

import "fmt"

func canJump(nums []int) bool {
	length := len(nums)
	max := 0
	if length <= 1 {
		return true
	}
	for i := 0; i < length; i++ {
		// 当前位置可到达
		if i <= max {
			if max < nums[i]+i {
				max = nums[i] + i
			}
			if max >= length-1 {
				return true
			}
		}
	}
	return false
}

func main() {
	nums := []int{3, 2, 1, 0, 4}
	fmt.Println(canJump(nums))
}

2020/4/18

leetcode 11. 盛水最多的容器_Go
package main

import (
	"fmt"
)

// 第一个反应就是two pointers
// 从两侧往中间遍历,一次o(n)即可
func maxArea(height []int) int {
	length := len(height)
	left, right := 0, length-1
	ans := 0
	for left < right {
		tempAns := (right - left) * min(height[left], height[right])
		if ans < tempAns {
			ans = tempAns
		}
		if height[left] < height[right] {
			left++
		} else {
			right--
		}
	}
	return ans
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func main() {
	height := []int{2, 3, 4, 5, 18, 17, 6}
	fmt.Println(maxArea(height))
}

leetcode 104. 二叉树的最大深度_C++

我们从本地的测试集开始写才是真正的写好一道题哦

不觉得构造一颗树更有收获么,开始重新回忆C++

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>

using namespace std;
// 104. 二叉树的最大深度
// 最大深度用DFS处理每个节点左右子树的深度即可

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

int maxDepth(TreeNode* root){
    if(root==NULL) return 0;
    int leftHeight=maxDepth(root->left);
    int rightHeight=maxDepth(root->right);
    return max(leftHeight,rightHeight)+1;
}

TreeNode* newNode(int v){
    TreeNode* node = new TreeNode(v);
}

TreeNode* CreateTree(int a[],int n){
    if (n==0){
        return NULL;
    }
    TreeNode* root=new TreeNode(a[0]);
    queue<TreeNode*> q;
    q.push(root);
    int num=1;
    while(num<n){
        TreeNode* top=q.front();
        q.pop();
        if(top->left==NULL){
            if(a[num]!=-1){
                top->left=new TreeNode(a[num]);
                q.push(top->left);
            }
            num++;
        }
        if(num==n){
            break;
        }
        if(top->right==NULL){
            if(a[num]!=-1){
                top->right=new TreeNode(a[num]);
                q.push(top->right);
            }
            num++;
        }
    }
    return root;
}

int main()
{
    int n;
    scanf("%d",&n); // 7
    int a[n]; // 3 9 20 -1 -1 15 7
    for(int i=0;i<n;i++){  // -1 represents NULL
        scanf("%d",&a[i]);
        //printf("%d\n",a[i]);
    }
    TreeNode* root=CreateTree(a,n);
    //printf("%d\n",root->val);
    //printf("%d\n",root->right->right->val);
    int ans=maxDepth(root);
    printf("%d\n",ans);
    return 0;
}

leetcode 101. 对称二叉树_C++

第一反应是懵的,看了一下官方题解,有个思路很重要

  1. 它们的两个根结点具有相同的值。
  2. 每个树的右子树都与另一个树的左子树镜像对称

什么我也能这么拆解题目就好了呢

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>

using namespace std;
// 101. 对称二叉树

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

bool isMirror(TreeNode* a,TreeNode* b){
    if(a==nullptr && b==nullptr) return true;
    if(a==nullptr || b==nullptr) return false;
    return ((a->val == b->val)&& isMirror(a->left, b->right)&& isMirror(b->left, a->right));
}

bool isSymmetric(TreeNode* root) {
    if(root==NULL){
        return true;
    }
    else{
        return isMirror(root->left,root->right);
    }
}

TreeNode* newNode(int v){
    TreeNode* node = new TreeNode(v);
}

TreeNode* CreateTree(int a[],int n){
    if (n==0){
        return NULL;
    }
    TreeNode* root=new TreeNode(a[0]);
    queue<TreeNode*> q;
    q.push(root);
    int num=1;
    while(num<n){
        TreeNode* top=q.front();
        q.pop();
        if(top->left==NULL){
            if(a[num]!=-1){
                top->left=new TreeNode(a[num]);
                q.push(top->left);
            }
            num++;
        }
        if(num==n){
            break;
        }
        if(top->right==NULL){
            if(a[num]!=-1){
                top->right=new TreeNode(a[num]);
                q.push(top->right);
            }
            num++;
        }
    }
    return root;
}

int main()
{
    int n;
    scanf("%d",&n); // 7
    int a[n]; // 1 2 2 3 4 4 3
    for(int i=0;i<n;i++){  // -1 represents NULL
        scanf("%d",&a[i]);
        //printf("%d\n",a[i]);
    }
    TreeNode* root=CreateTree(a,n);
    bool ans=isSymmetric(root);
    printf("%d\n",ans);
    return 0;
}

2020/4/19 && 20

leetcode 455. 分发饼干_C++
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>

using namespace std;
// 455. 分发饼干
int findContentChildren(vector<int>& g, vector<int>& s) {
    sort(g.begin(),g.end());
    sort(s.begin(),s.end());
    int gIndex=0;
    int num=0;
    for(int i=0;i<s.size();i++){
        if(gIndex==g.size()) break;
        if(g[gIndex]<=s[i]){
            num++;
            gIndex++;
        }
    }
    return num;
}

int main()
{
    vector<int> g,s;
    int n,m; // 3 2
    int temp;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){ // 1 2 3
        scanf("%d",&temp);
        g.push_back(temp);
    }
    for(int i=0;i<m;i++){ // 1 1
        scanf("%d",&temp);
        s.push_back(temp);
    }
    int ans=findContentChildren(g,s);
    printf("%d\n",ans);
    return 0;
}

leetcode 股票题C++

通解,花里胡哨的情况有一堆,打算采用暴力枚举dp状态的方式想把所有的题目都做了,然后再改进

所有题目的状态无非就是三类,天数(n);允许交易的最大次数(K);是否持有股票(0/1)

总状态开一个三维的dp数组能应付一切情况

leetcode 121. 买卖股票的最佳时机_C++

K==1,这个状态对dp没有什么影响了,成功降维省空间

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>

using namespace std;
// 121. 买卖股票的最佳时机
int maxProfit(vector<int>& prices) {
    int len=prices.size();
    if(len==0) return 0;
    int dp[100000][2];
    // 处理边界
    dp[0][0]=0;
    dp[0][1]=-prices[0];
    for(int i=1;i<len;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
        dp[i][1]=max(dp[i-1][1],-prices[i]);
    }
    return dp[len-1][0];
}

int main()
{
    int n,temp;
    scanf("%d",&n); // 6
    vector<int> prices;
    for(int i=0;i<n;i++){ // 7 1 5 3 6 4
        scanf("%d",&temp);
        prices.push_back(temp);
    }
    int ans=maxProfit(prices);
    printf("%d\n",ans);
    return 0;
}
leetcode 122. 买卖股票的最佳时机 II_C++

这次K变成了正无穷大

只展示maxProfit函数

我们推理一下状态转移公式

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
如果 k 为正无穷,那么就可以认为 k 和 k - 1 是一样的(很关键的一步)
这样就可以再次降维,丢弃k的那个维度
// 122. 买卖股票的最佳时机 II
int maxProfit2(vector<int>& prices) {
    int len=prices.size();
    if(len==0) return 0;
    int dp[100000][2];
    // 处理边界
    dp[0][0]=0;
    dp[0][1]=-prices[0];
    for(int i=1;i<len;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
        dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
    }
    return dp[len-1][0];
}
leetcode 123. 买卖股票的最佳时机 III_C++

仔细分析和上面的题目基本一样了,k为2

但是我实在是忍受不了0代表第一天了,就改了下下标

// 123. 买卖股票的最佳时机 III
// dp[i][j][k]表示第i天,进行了j次交易,当前状态为k时的最大利润
int maxProfit3(vector<int>& prices) {
    const int inf = 1 << 30;
    int len=prices.size();
    int dp[100001][3][2];
    // 处理边界
    for(int i=0;i<=len;i++){
        dp[i][0][0]=0;
        dp[i][0][1]=-inf;
    }
    for(int i=1;i<=2;i++){
        dp[0][i][0]=-inf;
        dp[0][i][1]=-inf;
    }
    // 状态转移方程
    for(int i=1;i<=len;i++){
        for(int j=0;j<=2;j++){
            dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]+prices[i-1]);
            if(j!=0)
                dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-prices[i-1]);
        }
    }
    return max(max(dp[len][0][0], dp[len][1][0]), dp[len][2][0]);
}
leetcode 188. 买卖股票的最佳时机IV_C++

这题只不过k变成了我们输入的值

然后做了一下发现出了个问题,样例中k可以为1000000000,我们直接开dp数组会超过可用的内存空间

所以我们需要对K>len/2的情况单独讨论

那么K上限是无穷大,对于本次问题没有约束力了,那么我们直接降维即可

// 188. 买卖股票的最佳时机 IV
int maxProfit(int k, vector<int>& prices) {
    if(k==0) return 0;
    const int inf = 1 << 30;
    int len=prices.size();
    if(len<2) return 0;
    int K=k;
    if (K>len/2){
        int maxpro=0;
        int dp2[len][2];
        dp2[0][0] = 0;
        dp2[0][1] = -prices[0];
        for (int i = 1; i < len; i++)
        {
            dp2[i][0] = max(dp2[i - 1][0], dp2[i - 1][1] + prices[i]);
            dp2[i][1] = max(dp2[i - 1][1], dp2[i - 1][0] - prices[i]);
            maxpro = max(max(dp2[i][0], dp2[i][1]), maxpro);
        }
        return maxpro;
    }
    int dp[len+1][K+1][2];
    // 处理边界
    for(int i=0;i<=len;i++){
        dp[i][0][0]=0;
        dp[i][0][1]=-inf;
    }
    for(int i=1;i<=K;i++){
        dp[0][i][0]=-inf;
        dp[0][i][1]=-inf;
    }
    // 状态转移方程
    for(int i=1;i<=len;i++){
        for(int j=0;j<=K;j++){
            dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]+prices[i-1]);
            if(j!=0)
                dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-prices[i-1]);
        }
    }
    int ans=dp[len][0][0];
    for(int i=1;i<=K;i++){
        ans=max(ans,dp[len][i][0]);
    }
    return ans;
}
leetcode 309. 最佳买卖股票时机含冷冻期_C++

可以看到对K没有限制,又可以降维了

// 309. 最佳买卖股票时机含冷冻期
int maxProfit(vector<int>& prices) {
    int n=prices.size();
    const int inf = 1 << 30;
    if(n<=1) return 0;
    int dp[n+1][2];
    dp[0][1]=-inf;
    dp[0][0]=0;
    dp[1][0]=0;
    dp[1][1]=-prices[0];
    for(int i=2;i<=n;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i-1]);
        dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i-1]);
    }
    return dp[n][0];
}

leetcode 714. 买卖股票的最佳时机含手续费_C++

easy,改改我们的参数就好了

// 714. 买卖股票的最佳时机含手续费
int maxProfit(vector<int>& prices, int fee) {
    int n=prices.size();
    const int inf = 1 << 30;
    if(n<=1) return 0;
    int dp[n+1][2];
    dp[0][1]=-inf;
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i-1]);
        dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i-1]-fee);
    }
    return dp[n][0];
}
leetcode 200. 岛屿数量_Go

一开始用的BFS,提交之后发现很慢,for嵌套的太多了,就用DFS又写了一次,快了些

package main

import "fmt"

// BFS
func numIslands(grid [][]byte) int {
	wayX := []int{0, 0, 1, -1}
	wayY := []int{1, -1, 0, 0}
	row := len(grid)
	if row == 0 {
		return 0
	}
	col := len(grid[0])
	num := 0
	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			if grid[i][j] == '1' {
				grid[i][j] = '2'
				num++
				queue := [][]int{}
				queue = append(queue, []int{i, j})
				for len(queue) != 0 {
					top := queue[0]
					queue = queue[1:]
					x, y := top[0], top[1]
					for z := 0; z < 4; z++ {
						newX := x + wayX[z]
						newY := y + wayY[z]
						if newX >= 0 && newX < row && newY >= 0 && newY < col && grid[newX][newY] == '1' {
							grid[newX][newY] = '2'
							queue = append(queue, []int{newX, newY})
						}
					}
				}
			}
		}
	}
	return num
}

// DFS
func numIslands2(grid [][]byte) int {
	row := len(grid)
	if row == 0 {
		return 0
	}
	col := len(grid[0])
	num := 0
	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			if grid[i][j] == '1' {
				num++
				dfs(grid, i, j)
			}
		}
	}
	return num
}

func dfs(grid [][]byte, r int, c int) {
	nr := len(grid)
	nc := len(grid[0])
	grid[r][c] = '0'
	if r-1 >= 0 && grid[r-1][c] == '1' {
		dfs(grid, r-1, c)
	}
	if r+1 < nr && grid[r+1][c] == '1' {
		dfs(grid, r+1, c)
	}
	if c-1 >= 0 && grid[r][c-1] == '1' {
		dfs(grid, r, c-1)
	}
	if c+1 < nc && grid[r][c+1] == '1' {
		dfs(grid, r, c+1)
	}
}

func main() {
	grid := [][]byte{
		{'1', '1', '0', '0', '0'},
		{'1', '1', '0', '0', '0'},
		{'0', '0', '1', '0', '0'},
		{'0', '0', '0', '1', '1'}}
	ans := numIslands2(grid)
	fmt.Println(ans)
}

并查集暂时不看了,有些遗忘,而且总觉得使用率不高

2020/4/21

leetcode 1248. 统计优美子数组_Go
package main

import "fmt"

// 奇数为1, 偶数为0, 子区间和为k的种类数
// 前缀和
// 有多少个sum-k,就有多少个k
func numberOfSubarrays(nums []int, k int) int {
	length := len(nums)
	for i := 0; i < length; i++ {
		if nums[i]&1 == 1 {
			nums[i] = 1
		} else {
			nums[i] = 0
		}
	}
	mp := make(map[int]int)
	sum, ans := 0, 0
	mp[0] = 1
	for i := 1; i <= length; i++ {
		sum += nums[i-1]
		x := sum - k
		ans += mp[x]
		mp[sum]++
	}
	return ans
}

func main() {
	nums := []int{2, 2, 2, 1, 2, 2, 1, 2, 2, 2}
	fmt.Println(numberOfSubarrays(nums, 2))
}

2020/4/22

leetcode 199. 二叉树的右视图_Go
package main

import "fmt"

// TreeNode struct
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func newNode(val int) *TreeNode {
	return &TreeNode{
		Val:   val,
		Left:  nil,
		Right: nil,
	}
}

func creatTree(a []int) *TreeNode {
	length := len(a)
	if length == 0 {
		return nil
	}
	node := newNode(a[0])
	queue := []*TreeNode{}
	queue = append(queue, node)
	num := 1
	for num < length {
		top := queue[0]
		queue = queue[1:]
		if top.Left == nil {
			if a[num] != -1 {
				top.Left = newNode(a[num])
				queue = append(queue, top.Left)
			}
			num++
		}
		if num == length {
			break
		}
		if top.Right == nil {
			if a[num] != -1 {
				top.Right = newNode(a[num])
				queue = append(queue, top.Right)
			}
			num++
		}
	}
	return node
}

// 层序遍历
func rightSideView(root *TreeNode) []int {
	if root == nil {
		return []int{}
	}
	ans := []int{}
	queue := []*TreeNode{}
	queue = append(queue, root)
	for len(queue) != 0 {
		size := len(queue)
		ans = append(ans, queue[0].Val)
		for i := 0; i < size; i++ {
			top := queue[0]
			queue = queue[1:]
			if top.Right != nil {
				queue = append(queue, top.Right)
			}
			if top.Left != nil {
				queue = append(queue, top.Left)
			}
		}
	}
	return ans
}

func main() {
	input := []int{1, 2, 3, -1, 5, -1, 4}
	root := creatTree(input)
	//fmt.Println(root)
	ans := rightSideView(root)
	fmt.Println(ans)
}

2020/4/23

leetcode 面试题 08.11. 硬币_Go
package main

import (
	"fmt"
	"math"
)

// 暴力数学算法
func waysToChange(n int) int {
	mod := int(math.Pow10(9)) + 7
	ans := 0
	for i := 0; i <= n/25; i++ {
		x := n - i*25
		y := x/5 + 1
		z := x/10 + 1
		ans += (y - z + 1) * z
		ans %= mod
	}
	return ans
}

func main() {
	fmt.Println(waysToChange(5))
}

2020/4/24

leetcode 面试题51. 数组中的逆序对_Go
package main

import "fmt"

// 第一反应双循环,但必定超时
// 归并排序
func reversePairs(nums []int) int {
	length := len(nums)
	if length < 2 {
		return 0
	}
	newNums := make([]int, length)
	temp := make([]int, length)
	copy(newNums, nums)
	return mergeSort(newNums, 0, length-1, temp)
}

func mergeSort(newNums []int, left int, right int, temp []int) int {
	if right == left {
		return 0
	}
	mid := left + (right-left)/2
	leftPairs := mergeSort(newNums, left, mid, temp)
	rightPairs := mergeSort(newNums, mid+1, right, temp)
	if newNums[mid] <= newNums[mid+1] {
		return leftPairs + rightPairs
	}
	cross := crossPairs(newNums, left, mid, right, temp)
	return cross + leftPairs + rightPairs
}

func crossPairs(newNums []int, left int, mid int, right int, temp []int) int {
	for i := left; i <= right; i++ {
		temp[i] = newNums[i]
	}
	i, j := left, mid+1
	count := 0
	for k := left; k <= right; k++ {
		if i == mid+1 {
			newNums[k] = temp[j]
			j++
		} else if j == right+1 {
			newNums[k] = temp[i]
			i++
		} else if temp[i] <= temp[j] {
			newNums[k] = temp[i]
			i++
		} else {
			newNums[k] = temp[j]
			j++
			count += (mid - i + 1)
		}
	}
	return count
}

func main() {
	nums := []int{7, 5, 6, 4}
	fmt.Println(reversePairs(nums))
}

2020/4/25 && 26

背包九讲_C++

题目来自ACWing

0/1背包问题
#include <iostream>
#include <stdio.h>
using namespace std;
// ACWing 0/1 package

const int n=1010;
int N,V;
int v[n]; // volume
int w[n]; // weight
int f[n][n];
int F[n];

// 基础二维状态
/*
    f[i][j] 根据前i件物品,且手头背包空间为j的时候,做出的最优选择
    1.若不选择第i件物品 f[i][j]=f[i-1][j]
    2.若选择了第i件物品 f[i][j]=f[i-1][j-v[i]]+w[i]
    f[i][j]=max{1,2}
    边界:
    f[0][j]=0
*/
int basicTwo(){
    scanf("%d%d",&N,&V);
    for(int i=1;i<=N;i++){
        scanf("%d%d",&v[i],&w[i]);
    }

    for(int i=1;i<=N;i++){
        for(int j=0;j<=V;j++){
            f[i][j]=f[i-1][j];
            if(j>=v[i]){
                f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
            }
        }
    }
    int ans=0;
    for(int i=0;i<=V;i++){
        ans=max(ans,f[N][i]);
    }
    return ans;
}

// 降维
/*
    每个f[i][j]只和上个f[i-1]的状态相关,没有必要记录全局的f[i][j]
    滚动数组
    为何要逆序循环可以画个表格观察
*/
int basicOne(){
    scanf("%d%d",&N,&V);
    for(int i=1;i<=N;i++){
        scanf("%d%d",&v[i],&w[i]);
    }

    for(int i=1;i<=N;i++){
        for(int j=V;j>=v[i];j--){
            F[j]=max(F[j],F[j-v[i]]+w[i]);
        }
    }
    int ans=0;
    ans=F[V];
    return ans;
}

int main()
{
    int ans=basicOne();
    printf("%d\n",ans);
    return 0;
}

完全背包问题
#include <iostream>
#include <stdio.h>
using namespace std;
// ACWing 完全背包问题
/*
    更进了一步,0/1背包每个物品只有选和不选
    完全背包可以放无穷次,在不超过背包限制的情况下
    那么在前i个物品,体积剩余j时,选择放k个物品,最基本的状态转移方程就需要三个for循环
    当然在一定条件下可以降维,慢慢分析
*/

const int n=1010;
int N,V;
int v[n]; // volume
int w[n]; // weight
int f[n][n];
int F[n];

// 基础的三维状态
/*
    f[i][j][k]
    f[i][j]=max(f[i-1][j-k*v[i]]+w[i]*k)  0<=k<=j/v[i]
    f[i][j]=max(f[i-1][j],f[i-1][j-k*v[i]]+w[i]*k)  1<=k<=j/v[i]
    遗憾的是,这么些会超时,so sad
*/
int basicThree(){
    scanf("%d%d",&N,&V);
    for(int i=1;i<=N;i++){
        scanf("%d%d",&v[i],&w[i]);
    }

    for(int i=1;i<=N;i++){
        for(int j=0;j<=V;j++){
            for(int k=0;k<=(j/v[i]);k++){
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    int ans=f[N][V];
    return ans;
}

/*
    优化写法
    f[i][j]-max{f[i-1][j],f[i][j-v[i]]+w[i]}
    推导过程就不写了
    比较一下f[i-1][j-k*v[i]]+k*w[i] 与 f[i][j-v]即可
*/
int better(){
    scanf("%d%d",&N,&V);
    for(int i=1;i<=N;i++){
        scanf("%d%d",&v[i],&w[i]);
    }

    for(int i=1;i<=N;i++){
        for(int j=0;j<=V;j++){
            f[i][j]=f[i-1][j];
            if(v[i]<=j){
                f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
            }
        }
    }
    int ans=f[N][V];
    return ans;
}

/*
    进一步优化就很简单了,和0/1背包的优化方式一样
*/

int best(){
    scanf("%d%d",&N,&V);
    for(int i=1;i<=N;i++){
        scanf("%d%d",&v[i],&w[i]);
    }

    for(int i=1;i<=N;i++){
        for(int j=V;j>=v[i];j--){
            F[j]=max(F[j],F[j-v[i]]+w[i]);
        }
    }
    int ans=F[V];
    return ans;
}

int main()
{
    int ans=best();
    printf("%d\n",ans);
    return 0;
}


leetcode 46. 全排列_Go
package main

import "fmt"

// 不会回溯法,直接看题解学习
func permute(nums []int) [][]int {
	ans := [][]int{}
	length := len(nums)
	if length == 0 {
		return ans
	}
	path := []int{}
	used := make([]bool, length)
	dfs(nums, length, path, used, &ans)
	return ans
}

func dfs(nums []int, count int, path []int, used []bool, ans *[][]int) {
	if len(path) == count {
		*ans = append(*ans, path)
		return
	}
	for i := 0; i < count; i++ {
		if used[i] != false {
			continue
		}
		used[i] = true
		x := append(path, nums[i])
		dfs(nums, count, x, used, ans)
		used[i] = false
	}
}

func main() {
	nums := []int{1, 2, 3}
	fmt.Println(permute(nums))
}

leetcode 23. 合并K个排序链表_Go
package main

import "fmt"

// ListNode : Definition for singly-linked list.
type ListNode struct {
	Val  int
	Next *ListNode
}

// 最朴素的想法就是合并k次
func mergeKLists(lists []*ListNode) *ListNode {
	k := len(lists)
	var ans *ListNode
	for i := 0; i < k; i++ {
		ans = mergeLists(ans, lists[i])
	}
	return ans
}

func mergeLists(a *ListNode, b *ListNode) *ListNode {
	head := ListNode{}
	tail := &head
	if a != nil && b == nil {
		return a
	} else if a == nil && b != nil {
		return b
	} else if a != nil && b != nil {
		for a != nil && b != nil {
			if a.Val < b.Val {
				tail.Next = a
				a = a.Next
			} else {
				tail.Next = b
				b = b.Next
			}
			tail = tail.Next
		}
	}
	if a != nil {
		tail.Next = a
	} else {
		tail.Next = b
	}
	return head.Next
}

func main() {
	l1 := &ListNode{}
	l1.Val = 1
	l1.Next = &ListNode{}
	l1.Next.Val = 4
	l1.Next.Next = &ListNode{}
	l1.Next.Next.Val = 5

	l2 := &ListNode{}
	l2.Val = 1
	l2.Next = &ListNode{}
	l2.Next.Val = 3
	l2.Next.Next = &ListNode{}
	l2.Next.Next.Val = 4

	l3 := &ListNode{}
	l3.Val = 2
	l3.Next = &ListNode{}
	l3.Next.Val = 6

	list := []*ListNode{l1, l2, l3}
	ans := mergeKLists(list)
	fmt.Println(ans.Val)
}

想要优化很容易想到就是直接类似于归并排序来提速

2020/4/27

leetcode 33. 搜索旋转排序数组_Go
package main

import "fmt"

// 时间复杂度怎么讲到o(logn)是个问题
// 想到的就是二分
// 但具体怎么操作还是走一步看一步的
func search(nums []int, target int) int {
	n := len(nums)
	if n == 0 {
		return -1
	}
	if n == 1 {
		if target == nums[0] {
			return 0
		}
		return -1
	}
	left, right := 0, n-1
	for left <= right {
		mid := left + (right-left)/2
		if nums[mid] == target {
			return mid
		}
		if nums[left] <= nums[mid] {
			if nums[left] <= target && target < nums[mid] {
				right = mid - 1
			} else {
				left = mid + 1
			}
		} else {
			if nums[mid] < target && target <= nums[right] {
				left = mid + 1
			} else {
				right = mid - 1
			}
		}
	}
	return -1
}

func main() {
	nums := []int{4, 5, 6, 7, 0, 1, 2}
	fmt.Println(search(nums, 0))
}

2020/4/28

今天主要配置了一下vscode下C++的配置,做点实验

leetcode 1. 两数之和_C++
#include<stdio.h>
#include<vector>

using namespace std;
// brute force

vector<int> twoSum(vector<int>& nums, int target) {
    vector<int> ans;
    int n=nums.size();
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            if(nums[i]+nums[j]==target){
                ans.push_back(i);
                ans.push_back(j);
            }
        }
    }
    return ans;
}

int main(){
    int a[4]={2, 7, 11, 15};
    vector<int> b(a,a+4);
    vector<int> ans=twoSum(b,9);
    printf("%d %d\n",ans[0],ans[1]);
    return 0;
}

#include<stdio.h>
#include<vector>
#include<map>

using namespace std;
// 说是说hashTable,我觉得map更方便

vector<int> twoSum(vector<int>& nums, int target) {
    vector<int> ans;
    map<int,int> mp;
    int n=nums.size();
    for(int i=0;i<n;i++){
        int rest=target-nums[i];
        if(mp.find(rest)!=mp.end()){
            map<int,int>::iterator it=mp.find(rest);
            ans.push_back(it->second);
            ans.push_back(i);
        }
        mp[nums[i]]=i;
    }
    return ans;
}

int main(){
    int a[4]={2, 7, 11, 15};
    vector<int> b(a,a+4);
    vector<int> ans=twoSum(b,9);
    printf("%d %d\n",ans[0],ans[1]);
    return 0;
    return 0;
}
leetcode 面试题56 - I. 数组中数字出现的次数_Go
package main

import "fmt"

// 时间复杂度是o(n)还是容易的,空间复杂度要是O(1),我们就不能hashTable了
// 直接看题解了,做法真的想不到
// 分组异或,位运算
func singleNumbers(nums []int) []int {
	temp := 0
	n := len(nums)
	for i := 0; i < n; i++ {
		temp ^= nums[i]
	}
	a, b := 0, 0
	mask := 1
	// find the last 1
	for mask&temp == 0 {
		mask <<= 1
	}
	temp = 0
	for i := 0; i < n; i++ {
		if mask&nums[i] == 0 {
			a ^= nums[i]
		} else {
			b ^= nums[i]
		}
	}
	return []int{a, b}
}

func main() {
	nums := []int{4, 1, 4, 6}
	fmt.Println(singleNumbers(nums))
}

2020/4/29

leetcode 1095. 山脉数组中查找目标值_Go
package main

import "fmt"

// MountainArray Struct
type MountainArray struct {
	array []int
	count int
}

func create(nums []int) *MountainArray {
	return &MountainArray{
		array: nums,
		count: len(nums),
	}
}
func (p *MountainArray) get(index int) int {
	if index >= p.count {
		return -1
	}
	return p.array[index]
}
func (p *MountainArray) length() int {
	return p.count
}

func findInMountainArray(target int, mountainArr *MountainArray) int {
	if mountainArr.length() == 0 {
		return -1
	}
	if mountainArr.length() == 1 {
		if mountainArr.get(0) == target {
			return 0
		}
		return -1
	}
	// find peak index
	left, right := 0, mountainArr.length()-1
	mid := 0
	for left < right {
		mid = left + (right-left)/2
		if mountainArr.get(mid) <= mountainArr.get(mid+1) {
			left = mid + 1
		} else {
			right = mid
		}
	}
	peakIndex := 0
	if mountainArr.get(mid) < mountainArr.get(mid+1) {
		peakIndex = mid + 1
	} else {
		peakIndex = mid
	}
	// find target
	left, right = 0, peakIndex
	for left < right {
		mid = left + (right-left)/2
		if mountainArr.get(mid) == target {
			return mid
		}
		if mountainArr.get(mid) < target {
			left = mid + 1
		} else {
			right = mid
		}
	}
	if right > 0 {
		mid = right
	}
	if mountainArr.get(mid) == target {
		return mid
	}
	if mid+1 < mountainArr.length() {
		if mountainArr.get(mid+1) == target {
			return mid + 1
		}
	}
	left, right = peakIndex, mountainArr.length()-1
	for left < right {
		mid = left + (right-left)/2
		if mountainArr.get(mid) == target {
			return mid
		}
		if mountainArr.get(mid) < target {
			right = mid
		} else {
			left = mid + 1
		}
	}
	if right > 0 {
		mid = right
	}
	if mountainArr.get(mid) == target {
		return mid
	}
	if mid+1 < mountainArr.length() {
		if mountainArr.get(mid+1) == target {
			return mid + 1
		}
	}
	return -1
}

func main() {
	array := []int{0, 5, 3, 1}
	nums := create(array)
	fmt.Println(nums)
	fmt.Println(findInMountainArray(1, nums))
}

2020/4/30
四月收官了,也做了不少算法题,最近压力也有一些,还算满意吧

leetcode 202. 快乐数_Go

package main
​
import "fmt"// 4月最后一天,leetcode希望我们快乐
func isHappy(n int) bool {
    mp := make(map[int]int, 10)
    temp := 0
    for n != 1 {
        temp = 0
        for n != 0 {
            temp = (n%10)*(n%10) + temp
            n /= 10
        }
        n = temp
        _, ok := mp[n]
        if ok {
            return false
        }
        mp[n] = 1
    }
    return true
}func main() {
    fmt.Println(isHappy(19))
}
​
快慢指针法,挂个官方的吧,很好理解

```go
func isHappy(n int) bool {
    slow, fast := n, step(n)
    for fast != 1 && slow != fast {
        slow = step(slow)
        fast = step(step(fast))
    }
    return fast == 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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试改文件编码格式、使用正确的字符集、换编辑器或者查找并替换特殊字符等方法来解决这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值