文章目录
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(¤t, 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(¤t, 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++
第一反应是懵的,看了一下官方题解,有个思路很重要
- 它们的两个根结点具有相同的值。
- 每个树的右子树都与另一个树的左子树镜像对称
什么我也能这么拆解题目就好了呢
#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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。