diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ae049917 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "D:\\golang\\algorithm018\\week04\\单词接龙\\main.go", + "showLog": true + } + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..dbeac5df --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module algorithm + +go 1.15 diff --git "a/week01/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" "b/week01/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" new file mode 100644 index 00000000..263ee25a --- /dev/null +++ "b/week01/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" @@ -0,0 +1,20 @@ +package main + +//两数之和 暴力求解,两重for循环 +//利用hash结构来做 nums的value为键,index为键 + +//参考官方推荐的例子 +func twoSum(nums []int, target int) []int { + hashTable := map[int]int{} + for i, x := range nums { + if p, ok := hashTable[target-x]; ok { + return []int{p, i} + } + hashTable[x] = i + } + return nil +} + +func main() { + +} diff --git "a/week01/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271/main.go" "b/week01/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271/main.go" new file mode 100644 index 00000000..4afb9074 --- /dev/null +++ "b/week01/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271/main.go" @@ -0,0 +1,29 @@ +package main + +//地址 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + +// 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + +// 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 + +// 示例1 给定数组 nums = [1,1,2], + +// 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + +// 你不需要考虑数组中超出新长度后面的元素。 + +// 重点 排序 如果乱序是得重新开辟空间来解决问题,就无法使用o(1)的空间完成 +func removeDuplicates(nums []int) int { + var j = 0 + for i := 1; i < len(nums); i++ { + if nums[i] != nums[j] { + j++ + nums[j] = nums[i] + } + } + return j + 1 +} + +func main() { + +} diff --git "a/week01/\345\212\240\344\270\200/main.go" "b/week01/\345\212\240\344\270\200/main.go" new file mode 100644 index 00000000..0186ee87 --- /dev/null +++ "b/week01/\345\212\240\344\270\200/main.go" @@ -0,0 +1,24 @@ +package main + +// 示例 1: + +// 输入: [1,2,3] +// 输出: [1,2,4] +// 解释: 输入数组表示数字 123。 + +// 如同10进制的加减法一样 反着处理应该更好 +// +func plusOne(digits []int) []int { + + for i := len(digits) - 1; i >= 0; i-- { + digits[i]++ + //参考 如果为0 ,则直接返回即可 + digits[i] = digits[i] % 10 + if digits[i] != 0 { + return digits + } + } + digits = append(digits, 0) + digits[0] = 1 + return digits +} diff --git "a/week01/\345\217\214\347\253\257\351\230\237\345\210\227/main.go" "b/week01/\345\217\214\347\253\257\351\230\237\345\210\227/main.go" new file mode 100644 index 00000000..530cb09d --- /dev/null +++ "b/week01/\345\217\214\347\253\257\351\230\237\345\210\227/main.go" @@ -0,0 +1,83 @@ +package main + +// 设计实现双端队列。 +// 你的实现需要支持以下操作: + +// MyCircularDeque(k):构造函数,双端队列的大小为k。 +// insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +// insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +// deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +// deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +// getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +// getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +// isEmpty():检查双端队列是否为空。 +// isFull():检查双端队列是否满了。 + +//双端队列 用前索引跟后索引确认当前数据 +type MyCircularDeque struct { + data []int + front int + end int +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + return MyCircularDeque{ + data: make([]int, k), + front: 0, + end: 0, + } +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertFront(value int) bool { + this.front = (len(this.data) + this.front - 1) % len(this.data) // 先循环左移一位 + this.data[this.front] = value // 填入数据 + return true +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertLast(value int) bool { + // 插入元素 + this.data[this.end] = value // 填入数据 + this.end = (this.end + 1) % len(this.data) // 循环右移一位 + return true +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteFront() bool { + this.front = (this.front + 1) % len(this.data) // 循环右移一位 + return true +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteLast() bool { + this.end = (len(this.data) + this.end - 1) % len(this.data) // 循环左移一位 + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + + // 获取头部元素 + return this.data[this.front] +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + return this.data[this.end] +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + return this.end == this.front +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + return (this.front+1)%len(this.data) == this.front +} + +func main() { + +} diff --git "a/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204/main.go" "b/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204/main.go" new file mode 100644 index 00000000..b1339da6 --- /dev/null +++ "b/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204/main.go" @@ -0,0 +1,41 @@ +package main + +import "fmt" + +// 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。 + +// 说明: + +// 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 +// 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + +//有序数组 +// 1 暴力破解法 使用多余的数组空间存放,然后再进行排序 +// 2 从小到大的数组 最优解肯定是从后往前处理数据 +// 利用原数组空间修改数据 而不是移动 +func merge(nums1 []int, m int, nums2 []int, n int) { + end1 := m - 1 + end2 := n - 1 + l := m + n - 1 + for end1 >= 0 && end2 >= 0 { + if nums1[end1] < nums2[end2] { + nums1[l] = nums2[end2] + end2-- + } else { + nums1[l] = nums1[end1] + end1-- + } + l-- + } + //碰到 [0] 1 [1] 1单元测试不通过 + for end2 >= 0 { + nums1[l] = nums2[end2] + l-- + end2-- + } + fmt.Print(nums1) +} + +func main() { + //测试还不知道咋个传值 merge([]int{0}, 1, []int{1}, 1) +} diff --git "a/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250/main.go" "b/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250/main.go" new file mode 100644 index 00000000..843a7fa5 --- /dev/null +++ "b/week01/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250/main.go" @@ -0,0 +1,76 @@ +package main + +// 示例: + +// 输入:1->2->4, 1->3->4 +// 输出:1->1->2->3->4->4 + +//1 利用新的数组存放元素,然后再构建链表 时间复杂度为o(n) 空间复杂度o(n) +//2 使用递归 由于是有序的,这个时候只需要修改链表的next的指针值即可 +//3 使用多余的存储空间 +type ListNode struct { + Val int + Next *ListNode +} + +// func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { +// if l1 == nil { +// return l2 +// } +// if l2 == nil { +// return l1 +// } +// if l1.Val < l2.Val { +// l1.Next = mergeTwoLists(l1.Next, l2) +// return l1 +// } else { +// l2.Next = mergeTwoLists(l1, l2.Next) +// return l2 +// } +// } + +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + tempNode := &ListNode{} + prev := &ListNode{} + prev = tempNode + for l1 != nil && l2 != nil { + if l1.Val < l2.Val { + tempNode.Next = l1 + l1 = l1.Next + } else { + tempNode.Next = l2 + l2 = l2.Next + } + tempNode = tempNode.Next + } + //容易遗忘的点,上面的跳出循环的条件是某个链表结束 所以剩下的节点一定是大于当前的所有点,直接拼接在后面即可 + if l1 == nil { + tempNode.Next = l2 + } else { + tempNode.Next = l1 + } + return prev.Next +} +func printNode(l1 *ListNode) { + for l1 != nil { + println(l1.Val) + l1 = l1.Next + } +} + +func main() { + l1 := &ListNode{Val: 1} + l2 := &ListNode{Val: 2} + l3 := &ListNode{Val: 4} + l1.Next = l2 + l2.Next = l3 + + l4 := &ListNode{Val: 1} + l5 := &ListNode{Val: 3} + l6 := &ListNode{Val: 4} + + l4.Next = l5 + l5.Next = l6 + + printNode(mergeTwoLists(l1, l4)) +} diff --git "a/week01/\346\216\245\351\233\250\346\260\264/main.go" "b/week01/\346\216\245\351\233\250\346\260\264/main.go" new file mode 100644 index 00000000..f788be50 --- /dev/null +++ "b/week01/\346\216\245\351\233\250\346\260\264/main.go" @@ -0,0 +1,42 @@ +package main + +//https://leetcode-cn.com/problems/trapping-rain-water/ + +//这个题有点搞不懂get到题的核心 +//所以第一次完成看答案去反查如何解决问题 + +// 先用自己好理解的双指针法,这点跟寻找最大的面积那道题不一样 +// 我们得首先明白,木桶原理,当前容纳得面积得按照最小的处理 + +//输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] +// 输出:6 +func trap(height []int) int { + var left, right = 0, len(height) - 1 + var result, leftMax, rightMax int + for left < right { + if height[left] < height[right] { + if height[left] >= leftMax { + //设置左边最高柱子 + leftMax = height[left] + } else { + //右边必定有柱子挡水,所以,遇到所有值小于等于leftMax的,全部加入水池 + result += leftMax - height[left] + } + left++ + } else { + if height[right] > rightMax { + //设置右边最高柱子 + rightMax = height[right] + } else { + //左边必定有柱子挡水,所以,遇到所有值小于等于rightMax的,全部加入水池 + result += rightMax - height[right] + } + right-- + } + } + return result +} + +func main() { + trap([]int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}) +} diff --git "a/week01/\346\227\213\350\275\254\346\225\260\347\273\204/main.go" "b/week01/\346\227\213\350\275\254\346\225\260\347\273\204/main.go" new file mode 100644 index 00000000..aa93e20f --- /dev/null +++ "b/week01/\346\227\213\350\275\254\346\225\260\347\273\204/main.go" @@ -0,0 +1,42 @@ +package main + +import "fmt" + +//给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数 + +// 示例 1: + +// 输入: [1,2,3,4,5,6,7] 和 k = 3 +// 输出: [5,6,7,1,2,3,4] +// 解释: +// 向右旋转 1 步: [7,1,2,3,4,5,6] +// 向右旋转 2 步: [6,7,1,2,3,4,5] +// 向右旋转 3 步: [5,6,7,1,2,3,4] + +// 说明: + +// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +// 要求使用空间复杂度为 O(1) 的 原地 算法。 + +//1 暴力破解法 也不能立刻做出来 +//2 环形结构,如何移动 +//2.1 边界条件 不太能立刻get到 + +//3 反转数组 +func rotate(nums []int, k int) { + k %= len(nums) + reverse(nums, 0, len(nums)-1) + reverse(nums, 0, k-1) + reverse(nums, k, len(nums)-1) +} +func reverse(nums []int, start, end int) { + for start < end { + nums[start], nums[end] = nums[end], nums[start] + start++ + end-- + } +} + +func main() { + fmt.Print(7 % 3) +} diff --git "a/week01/\347\247\273\345\212\2500/main.go" "b/week01/\347\247\273\345\212\2500/main.go" new file mode 100644 index 00000000..38c7115b --- /dev/null +++ "b/week01/\347\247\273\345\212\2500/main.go" @@ -0,0 +1,25 @@ +package main + +//必须在原数组上操作,不能拷贝额外的数组。 +// 尽量减少操作次数。 + +//以前可能会想用额外的数组处理 + +// 示例: + +// 输入: [0,1,0,3,12] +// 输出: [1,3,12,0,0] +func moveZeroes(nums []int) { + j := 0 + for i := 0; i < len(nums); i++ { + //犯了个错,没考虑到负数情况 + if nums[i] != 0 { + nums[j], nums[i] = nums[i], nums[j] + j++ + } + } +} + +func main() { + +} diff --git "a/week02/HashMap\346\200\273\347\273\223.md" "b/week02/HashMap\346\200\273\347\273\223.md" new file mode 100644 index 00000000..151acdde --- /dev/null +++ "b/week02/HashMap\346\200\273\347\273\223.md" @@ -0,0 +1,14 @@ +## HashMap + +### 实现方式 + +- 数据+链表 +> 用链地址去解决hash冲突的问题 +- 红黑树 + +> 当map增长到指定的阈值的时候,数组就不适用了,升高维度进化为树。但因为对树了解不太多,等后面学完再补充 +### 解决问题 + +- 访问只需要o(1)的时间复杂度 + +- 常作为缓存使用 \ No newline at end of file diff --git a/week02/NOTE.md b/week02/NOTE.md index 50de3041..f2b21aba 100644 --- a/week02/NOTE.md +++ b/week02/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file + +所有数的处理,递归是核心 +## 问题 + +- 使用golang封装的堆处理问题,但是不太熟练,还需练习 +- dfs+bfs有待琢磨下,算法模板还是挺有趣的 + +## 脑图在修改中 +- 预计11-08号完成前两章的脑图 diff --git "a/week02/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206/main.go" "b/week02/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206/main.go" new file mode 100644 index 00000000..a490c57f --- /dev/null +++ "b/week02/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206/main.go" @@ -0,0 +1,25 @@ +package main + +type Node struct { + Val int + Children []*Node +} + +//N叉树的前序遍历 +//root->left-> right +//root->孩子 +func preorder(root *Node) (result []int) { + var order func(root *Node) + + order = func(root *Node) { + if root != nil { + result = append(result, root.Val) + for _, value := range root.Children { + order(value) + } + } + } + order(root) + return nil + +} diff --git "a/week02/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206/main.go" "b/week02/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206/main.go" new file mode 100644 index 00000000..ce47e0f6 --- /dev/null +++ "b/week02/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206/main.go" @@ -0,0 +1,33 @@ +package main + +type Node struct { + Val int + Children []*Node +} + +func levelOrder(root *Node) [][]int { + res := [][]int{} + if root == nil { + return nil + } + dfs(root, 0, &res) + return res +} + +//题目看着挺吓人,不过记住规则就好 深度遍历 +func dfs(root *Node, level int, res *[][]int) { + if root == nil { + return + } + if len(*res) == level { + *res = append(*res, []int{}) + } + (*res)[level] = append((*res)[level], root.Val) + for _, n := range root.Children { + dfs(n, level+1, res) + } +} + +func main() { + +} diff --git "a/week02/\344\270\221\346\225\260/ugly.go" "b/week02/\344\270\221\346\225\260/ugly.go" new file mode 100644 index 00000000..99842d20 --- /dev/null +++ "b/week02/\344\270\221\346\225\260/ugly.go" @@ -0,0 +1,40 @@ +package main + +// 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。 + +//这个题有点难理解,不过只要理解题意做还是挺方便的 2* 3* 5* 第n个数一定是这些之中的一个,并且会排序从小到大 +//定义一个数组存放所有的丑数 +//所以这就是动态规划? +func min(x, y int) int { + if x < y { + return x + } + return y +} + +func nthUglyNumber(n int) int { + //创建3个索引指针 + var a, b, c int + result := make([]int, n, n) + result[0] = 1 + for i := 1; i < n; i++ { + result[i] = min(result[c]*5, min(result[a]*2, result[b]*3)) + + //每次都选择最小的值 + if result[i] == result[a]*2 { + a++ + } + if result[i] == result[b]*3 { + b++ + } + if result[i] == result[c]*5 { + c++ + } + + } + return result[n-1] +} + +func main() { + +} diff --git "a/week02/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" "b/week02/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" new file mode 100644 index 00000000..e5a395c5 --- /dev/null +++ "b/week02/\344\270\244\346\225\260\344\271\213\345\222\214/main.go" @@ -0,0 +1,17 @@ +package main + +//已经做过的题 +func twoSum(nums []int, target int) []int { + hashTable := map[int]int{} + for i, x := range nums { + if p, ok := hashTable[target-x]; ok { + return []int{p, i} + } + hashTable[x] = i + } + return nil +} + +func main() { + +} diff --git "a/week02/\344\272\214\345\217\211\346\240\221\345\211\215\345\272\217\344\270\255\345\272\217/tree.go" "b/week02/\344\272\214\345\217\211\346\240\221\345\211\215\345\272\217\344\270\255\345\272\217/tree.go" new file mode 100644 index 00000000..1152e0c8 --- /dev/null +++ "b/week02/\344\272\214\345\217\211\346\240\221\345\211\215\345\272\217\344\270\255\345\272\217/tree.go" @@ -0,0 +1,59 @@ +package tree + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +//中序遍历 left-root-right +func inorderTraversal(root *TreeNode) (result []int) { + var order func(root *TreeNode) + + order = func(root *TreeNode) { + if root != nil { + order(root.Left) + result = append(result, root.Val) + order(root.Right) + + } + } + order(root) + return nil +} + +//前序遍历 root-left-right +func preorderTraversal(root *TreeNode) (result []int) { + var order func(root *TreeNode) + + order = func(root *TreeNode) { + if root != nil { + result = append(result, root.Val) + order(root.Left) + order(root.Right) + } + } + order(root) + return nil + +} + +// class Solution { + +// private List> result = new ArrayList<>(); + +// public List> levelOrder(Node root) { +// if (root != null) traverseNode(root, 0); +// return result; +// } + +// private void traverseNode(Node node, int level) { +// if (result.size() <= level) { +// result.add(new ArrayList<>()); +// } +// result.get(level).add(node.val); +// for (Node child : node.children) { +// traverseNode(child, level + 1); +// } +// } +// } diff --git "a/week02/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240/main.go" "b/week02/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240/main.go" new file mode 100644 index 00000000..6c04b596 --- /dev/null +++ "b/week02/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240/main.go" @@ -0,0 +1,53 @@ +package main + +import ( + "container/heap" + "fmt" +) + +// 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 + +//想到了用堆来解决 + +//前K个频率高的元素 +func topKFrequent(nums []int, k int) []int { + mc := make(map[int]int) + for _, value := range nums { + mc[value]++ + } + + h := &head{} + heap.Init(h) + + for key, value := range mc { + heap.Push(h, [2]int{key, value}) + if h.Len() > k { + heap.Pop(h) + } + } + ret := make([]int, k) + for i := 0; i < k; i++ { + ret[k-i-1] = heap.Pop(h).([2]int)[0] + } + return ret +} + +type head [][2]int + +func (h head) Len() int { return len(h) } +func (h head) Less(i, j int) bool { return h[i][1] < h[j][1] } +func (h head) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func (h *head) Push(x interface{}) { + *h = append(*h, x.([2]int)) +} + +func (h *head) Pop() interface{} { + x := (*h)[h.Len()-1] + *h = (*h)[:h.Len()-1] + return x +} + +func main() { + fmt.Print(topKFrequent([]int{1, 2}, 2)) +} diff --git "a/week02/\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204/main.go" "b/week02/\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204/main.go" new file mode 100644 index 00000000..1446aaa4 --- /dev/null +++ "b/week02/\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204/main.go" @@ -0,0 +1,39 @@ +package main + +import "sort" + +type bytes []byte + +// 自定义排序规则 +func (b bytes) Len() int { + return len(b) +} +func (b bytes) Less(i, j int) bool { + return b[i] < b[j] +} +func (b bytes) Swap(i, j int) { + b[i], b[j] = b[j], b[i] +} + +func groupAnagrams(strs []string) [][]string { + var result [][]string + mk := make(map[string]int) + + for _, str := range strs { + //没有提供合适的方法,重写了 + temp := bytes(str) + sort.Sort(temp) // 将字符串排序 + k := string(temp) + if idx, ok := mk[k]; !ok { + mk[k] = len(result) + result = append(result, []string{str}) + } else { + result[idx] = append(result[idx], str) + } + } + return result +} + +func main() { + +} diff --git "a/week02/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215/main.go" "b/week02/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215/main.go" new file mode 100644 index 00000000..4f3a19c1 --- /dev/null +++ "b/week02/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215/main.go" @@ -0,0 +1,20 @@ +package main + +//什么是异位词 +//输入是通过将 s 的字母重新排列成 t 来生成变位词。 +// 因此,如果 t 是 s 的变位词,对两个字符串进行排序将产生两个相同的字符串。 +//Map解决 又快又好用 +func isAnagram(s string, t string) bool { + m := make(map[rune]int) + for _, value := range s { + m[value]++ + } + for _, value := range t { + m[value]-- + } + return len(m) == 0 +} + +func main() { + +} diff --git a/week03/NOTE.md b/week03/NOTE.md index 50de3041..96a262eb 100644 --- a/week03/NOTE.md +++ b/week03/NOTE.md @@ -1 +1,44 @@ -学习笔记 \ No newline at end of file +# 心得 + +这周东西确实花时间相对较少,又遇到了这种递归回溯法。发现与解决二叉树感觉如果进入了新的世界,在国际站上找到了一些比较优秀的解法。参考才能完成当前的作业 + + +加油把~~day day up + + + +## 牢记模板 + +```java +public void recur(int level, int param) { + // terminator + if (level > MAX_LEVEL) { + // process result + return; + } + // process current logic + process(level, param); + // drill down + recur( level: level + 1, newParam); + // restore current status + +} +``` +- 找到当前层的边界值 +- 处理当前层的逻辑 +- 接着向下走 +```golang + +func recur(level int ,parm int){ + // terminator + if level > MAX_LEVEL { + // process result + return; + } + // process current logic + process(level, param); + // drill down + recur(level + 1, newParam); + // restore current status +} +``` \ No newline at end of file diff --git "a/week03/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210/main.go" "b/week03/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210/main.go" new file mode 100644 index 00000000..1c85baaf --- /dev/null +++ "b/week03/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210/main.go" @@ -0,0 +1,36 @@ +// 236题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + +// 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。 +package main + +//TreeNode 根节点 +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +//分析 +// 从左+从右 一起找 +// 假设节点分布在左边与右边,就返回当前root + +// 如果排列在一边 则只返回q或者q的一个节点即可 +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + //边界情况 + if root == nil || root == p || root == q { + return root + } + + //进入下一层 + left := lowestCommonAncestor(root.Left, p, q) + right := lowestCommonAncestor(root.Right, p, q) + + //处理逻辑 + if left == nil { + return right + } else if right == nil { + return left + } else { + return root + } +} diff --git "a/week03/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221/main.go" "b/week03/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221/main.go" new file mode 100644 index 00000000..01fdea40 --- /dev/null +++ "b/week03/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221/main.go" @@ -0,0 +1,63 @@ +package main + +//TreeNode 根节点 +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +// 根据一棵树的前序遍历与中序遍历构造二叉树。 + +// 注意: +// 你可以假设树中没有重复的元素。 + +// 例如,给出 + +// 前序遍历 preorder = [3,9,20,15,7] +// 中序遍历 inorder = [9,3,15,20,7] + +//分析 + +//1 前序第一个点 就是根节点 +//2 通过根节点将 将中序遍历的数组分成两部分 left right + +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +//第一次 从前序找到根节点 1 中序 left 4 2 5 right 3 + +//所以问题变成了 如何合理拆分 +//left 前序 start,start+左子树的长度 中序 start ,根节点-1 +//right 前序 start+左子树的长度+1 end 中序 根节点+1 end + +func buildTree(preorder []int, inorder []int) *TreeNode { + ma := make(map[int]int) + + for i := 0; i < len(inorder); i++ { + ma[inorder[i]] = i + } + + var a func(preorder []int, preStart, preEnd int, inorder []int, inStart, inEnd int, ma map[int]int) *TreeNode + + a = func(preorder []int, preStart, preEnd int, inorder []int, inStart, inEnd int, inMap map[int]int) *TreeNode { + //跳出递归的条件 前序或者中序的整个数据长度遍历完 + if preStart > preEnd || inStart > inEnd { + return nil + } + root := &TreeNode{Val: preorder[preStart]} + inorderRoot := ma[root.Val] + //左子树的长度 + leftTreeLen := inorderRoot - inStart + + root.Left = a(preorder, preStart+1, preStart+leftTreeLen, inorder, inStart, inorderRoot-1, inMap) + //preStart+leftTreeLen+1 有点不懂先记录着回看再想明白 + root.Right = a(preorder, preStart+leftTreeLen+1, preEnd, inorder, inorderRoot+1, inEnd, inMap) + + return root + } + + return a(preorder, 0, len(preorder)-1, inorder, 0, len(inorder)-1, ma) +} diff --git "a/week03/\345\205\250\346\216\222\345\210\227/main.go" "b/week03/\345\205\250\346\216\222\345\210\227/main.go" new file mode 100644 index 00000000..d494a771 --- /dev/null +++ "b/week03/\345\205\250\346\216\222\345\210\227/main.go" @@ -0,0 +1,43 @@ +package main + +// 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 + +// 示例: + +// 输入: [1,2,3] +// 输出: +// [ +// [1,2,3], +// [1,3,2], +// [2,1,3], +// [2,3,1], +// [3,1,2], +// [3,2,1] +// ] + +// 从国际版找到的一个比较好的解决办法 +// 自己写总是会出现bug + +func permute(nums []int) [][]int { + result := &[][]int{} + dfs(0, nums, result) + return *result +} + +func dfs(start int, nums []int, results *[][]int) { + if start == len(nums) { + tmp := make([]int, len(nums)) + copy(tmp, nums) + *results = append(*results, tmp) + return + } + for i := start; i < len(nums); i++ { + nums[i], nums[start] = nums[start], nums[i] + dfs(start+1, nums, results) + nums[i], nums[start] = nums[start], nums[i] + } +} + +func main() { + +} diff --git "a/week03/\345\205\250\346\216\222\345\210\2272/main.go" "b/week03/\345\205\250\346\216\222\345\210\2272/main.go" new file mode 100644 index 00000000..5f3c307f --- /dev/null +++ "b/week03/\345\205\250\346\216\222\345\210\2272/main.go" @@ -0,0 +1,31 @@ +package main + +//比上面多了一个判断是否重复的就可以了 +func permuteUnique(nums []int) [][]int { + result := &[][]int{} + dfs(0, 1, nums, result) + return *result +} + +func dfs(start, k int, nums []int, results *[][]int) { + if k == len(nums) { + tmp := make([]int, len(nums)) + copy(tmp, nums) + *results = append(*results, tmp) + return + } + used := make(map[int]int) + for i := start; i < len(nums); i++ { + if _, ok := used[nums[i]]; ok { + continue + } + nums[i], nums[start] = nums[start], nums[i] + dfs(start+1, k+1, nums, results) + nums[i], nums[start] = nums[start], nums[i] + used[nums[i]] = i + } +} + +func main() { + +} diff --git "a/week03/\347\273\204\345\220\210/main.go" "b/week03/\347\273\204\345\220\210/main.go" new file mode 100644 index 00000000..ee954f56 --- /dev/null +++ "b/week03/\347\273\204\345\220\210/main.go" @@ -0,0 +1,35 @@ +package main + +import "fmt" + +//NO 77 +//给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 +// 心里是蒙蔽的,咋的这递归完全就不一样了,思考方式都不同了 +// 看了第三遍的题解 有一点点感觉,但还是理解不了 +func combine(n int, k int) [][]int { + results := [][]int{} + if k > n { + return results + } + + dfs(n, k, 1, []int{}, &results) + return results +} + +func dfs(n int, k, begin int, buf []int, results *[][]int) { + if k == 0 { + tmp := make([]int, len(buf)) + copy(tmp, buf) + *results = append(*results, tmp) + return + } + for i := begin; i <= n; i++ { + buf = append(buf, i) + dfs(n, k-1, i+1, buf, results) + buf = buf[:len(buf)-1] + } +} + +func main() { + fmt.Println(combine(4, 2)) +} diff --git a/week04/NOTE.md b/week04/NOTE.md index 50de3041..9d341117 100644 --- a/week04/NOTE.md +++ b/week04/NOTE.md @@ -1 +1 @@ -学习笔记 \ No newline at end of file +整体而言,有几个题很难理解。有点死磕题目了,导致后续没有完成全部内容。都只刷了一遍题目 diff --git "a/week04/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II/main.go" "b/week04/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II/main.go" new file mode 100644 index 00000000..0564e336 --- /dev/null +++ "b/week04/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II/main.go" @@ -0,0 +1,18 @@ +package main + +// 122. 买卖股票的最佳时机 II + +//这个题就是期望今天一直比昨天的行情好 +func maxProfit(prices []int) (ans int) { + for i := 1; i < len(prices); i++ { + ans += max(0, prices[i]-prices[i-1]) + } + return +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git "a/week04/\345\210\206\345\217\221\351\245\274\345\271\262/main.go" "b/week04/\345\210\206\345\217\221\351\245\274\345\271\262/main.go" new file mode 100644 index 00000000..0aa17db1 --- /dev/null +++ "b/week04/\345\210\206\345\217\221\351\245\274\345\271\262/main.go" @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "sort" +) + +// 455. 分发饼干 + +//先排序 然后两个数组依次配对 +func findContentChildren(g []int, s []int) int { + sort.Ints(g) + sort.Ints(s) + fmt.Print(g) + fmt.Print(s) + i, j := 0, 0 + for i < len(g) && j < len(s) { + if g[i] <= s[j] { + i++ + } + j++ + } + return i +} diff --git "a/week04/\345\215\225\350\257\215\346\216\245\351\276\231/main.go" "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231/main.go" new file mode 100644 index 00000000..bf9dfcf2 --- /dev/null +++ "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231/main.go" @@ -0,0 +1,153 @@ +package main + +import ( + "fmt" +) + +// 127. 单词接龙 + +// 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + +// 每次转换只能改变一个字母。 +// 转换过程中的中间单词必须是字典中的单词。 +// 说明: + +// 如果不存在这样的转换序列,返回 0。 +// 所有单词具有相同的长度。 +// 所有单词只由小写字母组成。 +// 字典中不存在重复的单词。 +// 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + +// 示例 1: + +// 输入: +// beginWord = "hit", +// endWord = "cog", +// wordList = ["hot","dot","dog","lot","log","cog"] +//"hot", "dot", "dog", "lot", "log" + +// 输出: 5 + +// 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 + +// 耗时3小时+ + +//问题 1 单向递归被判超时,不知道是什么机制 +//问题 2 对golang的使用出现了致命的失误 + +//问题3 当遇到这种测试的时候出现问题 +//"ymain" +// "oecij" +// ["ymann","yycrj","oecij","ymcnj","yzcrj","yycij","xecij","yecij","ymanj","yzcnj","ymain"] + +//总之在个题耗费 2020-11-15一下午的时间 +func main() { + fmt.Println(ladderLength("ymain", "oecij", []string{"ymann", "yycrj", "oecij", "ymcnj", "yzcrj", "yycij", "xecij", "yecij", "ymanj", "yzcnj", "ymain"})) + + // fmt.Println(ladderLength("hit", "cog", []string{"hot", "dot", "dog", "lot", "log", "cog"})) +} + +func ladderLength(beginWord string, endWord string, wordList []string) int { + wordmap := make(map[string]bool) + for _, value := range wordList { + wordmap[value] = true + } + if _, ok := wordmap[endWord]; !ok { + return 0 + } + + visited := make(map[string]bool) + beginqueue := new([]string) + endqueue := new([]string) + *beginqueue = append(*beginqueue, beginWord) + *endqueue = append(*endqueue, endWord) + + if _, ok := wordmap[beginWord]; ok { + delete(wordmap, beginWord) + } + + count := 1 + for len(*beginqueue) > 0 && len(*endqueue) > 0 { + res := find(count, beginqueue, endqueue, visited, wordmap) + + if res != -1 { + return res + } + count++ + } + return 0 +} +func find(min int, beginqueue, endqueue *[]string, visited, dict map[string]bool) int { + var count int + pre := false + start := len(*beginqueue) + end := len(*endqueue) + + if start <= end { + count = start + pre = true + } else { + count = end + } + fmt.Println(*beginqueue, *endqueue, visited, count, pre) + + for i := 0; i < count; i++ { + var value string + if pre { + value = (*beginqueue)[0] + *beginqueue = (*beginqueue)[1:] + } else { + value = (*endqueue)[0] + *endqueue = (*endqueue)[1:] + } + chs := []byte(value) + for j := 0; j < len(chs); j++ { + for c := 'a'; c <= 'z'; c++ { + if byte(c) == chs[j] { + continue + } + old := chs[j] + chs[j] = byte(c) + target := string(chs) + if _, ok := dict[target]; ok { + if pre { + if contains(*endqueue, target) { + // fmt.Println(pre, *endqueue, target) + return min + 1 + } + ok := visited[target] + if !ok { + *beginqueue = append(*beginqueue, target) + visited[target] = true + } + + } else { + if contains(*beginqueue, target) { + fmt.Println(*beginqueue, target) + return min + 1 + } + ok := visited[target] + if !ok { + *endqueue = append(*endqueue, target) + visited[target] = true + } + + } + } + + chs[j] = old + } + } + } + return -1 +} + +func contains(word []string, taget string) bool { + for _, value := range word { + if value == taget { + return true + } + } + return false +} diff --git "a/week04/\345\215\225\350\257\215\346\216\245\351\276\231/\345\217\214\345\220\221bfs.png" "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231/\345\217\214\345\220\221bfs.png" new file mode 100644 index 00000000..b56f86c0 Binary files /dev/null and "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231/\345\217\214\345\220\221bfs.png" differ diff --git "a/week04/\345\215\225\350\257\215\346\216\245\351\276\231II/main.go" "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231II/main.go" new file mode 100644 index 00000000..a59bdf1a --- /dev/null +++ "b/week04/\345\215\225\350\257\215\346\216\245\351\276\231II/main.go" @@ -0,0 +1,32 @@ +package main + +//126 + +// 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则: + +// 每次转换只能改变一个字母。 +// 转换后得到的单词必须是字典中的单词。 +// 说明: + +// 如果不存在这样的转换序列,返回一个空列表。 +// 所有单词具有相同的长度。 +// 所有单词只由小写字母组成。 +// 字典中不存在重复的单词。 +// 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + +// 示例 1: + +// 输入: +// beginWord = "hit", +// endWord = "cog", +// wordList = ["hot","dot","dog","lot","log","cog"] + +// 输出: +// [ +// ["hit","hot","dot","dog","cog"], +//   ["hit","hot","lot","log","cog"] +// ] + +func main() { + +} diff --git "a/week04/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274/main.go" "b/week04/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274/main.go" new file mode 100644 index 00000000..1e97fe7d --- /dev/null +++ "b/week04/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274/main.go" @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" +) + +// 153. 寻找旋转排序数组中的最小值 + +//假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。 + +// 请找出其中最小的元素。 + +//解题 找到旋转点即可 +func findMin(nums []int) int { + if len(nums) == 1 { + return nums[0] + } + + left := 0 + right := len(nums) - 1 + if nums[right] > nums[0] { + return nums[0] + + } + for left <= right { + mid := (left + right) / 2 + if nums[mid] > nums[mid+1] { + return nums[mid+1] + } + if nums[mid-1] > nums[mid] { + return nums[mid] + } + if nums[mid] > nums[0] { + left = mid + 1 + } else { + right = mid - 1 + } + fmt.Println(left, right, mid) + } + return -1 +} + +func main() { + fmt.Println(findMin([]int{4, 5, 6, 7})) +} diff --git "a/week04/\345\262\233\345\261\277\346\225\260\351\207\217/main.go" "b/week04/\345\262\233\345\261\277\346\225\260\351\207\217/main.go" new file mode 100644 index 00000000..4a22fda1 --- /dev/null +++ "b/week04/\345\262\233\345\261\277\346\225\260\351\207\217/main.go" @@ -0,0 +1,38 @@ +package main + +import "fmt" + +// 200. 岛屿数量 +// 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。 + +//dfs深度优先遍历 + +func numIslands(grid [][]byte) int { + count := 0 + for i := 0; i < len(grid); i++ { + for j := 0; j < len(grid[i]); j++ { + if grid[i][j] == '1' { + count++ + fmt.Println(count) + dfs(i, j, grid) + } + + } + } + return count +} + +func dfs(i, j int, grid [][]byte) { + if i < 0 || j < 0 || i >= len(grid) || j >= len(grid[i]) || grid[i][j] == '0' { + return + } + grid[i][j] = '0' + dfs(i-1, j, grid) + dfs(i+1, j, grid) + dfs(i, j-1, grid) + dfs(i, j+1, grid) +} + +func main() { + +} diff --git "a/week04/\346\211\253\351\233\267\346\270\270\346\210\217/main.go" "b/week04/\346\211\253\351\233\267\346\270\270\346\210\217/main.go" new file mode 100644 index 00000000..5bb6336d --- /dev/null +++ "b/week04/\346\211\253\351\233\267\346\270\270\346\210\217/main.go" @@ -0,0 +1,55 @@ +package main + +//dfs 题目 +//上下左右斜线的8个方法 ,这个是需要dfs 判断当前是否需要改变 +var dx = []int{-1, 0, 1, -1, 1, 0, 1, -1} +var dy = []int{-1, 1, 1, 0, -1, -1, 0, 1} + +func updateBoard(board [][]byte, click []int) [][]byte { + x := click[0] + y := click[1] + //遇到炸弹直接返回 + if board[x][y] == 'M' { + board[x][y] = 'X' + return board + } + dfs(board, x, y) + return board +} + +func dfs(board [][]byte, x, y int) { + if x < 0 || x >= len(board) || y < 0 || y >= len(board[0]) || board[x][y] != 'E' { + return + } + num := getNumsOfBombs(board, x, y) + if num == 0 { + board[x][y] = 'B' + for i := 0; i < 8; i++ { + nx := x + dx[i] + ny := y + dy[i] + dfs(board, nx, ny) + } + } else { + board[x][y] = byte('0' + num) + } +} + +func getNumsOfBombs(board [][]byte, x, y int) int { + + num := 0 + for i := 0; i < 8; i++ { + nx := x + dx[i] + ny := y + dy[i] + if nx < 0 || nx >= len(board) || ny < 0 || ny >= len(board[0]) { + continue + } + if board[nx][ny] == 'M' || board[nx][ny] == 'X' { + num++ + } + } + return num +} + +func main() { + +} diff --git "a/week04/\346\216\242\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265/main.go" "b/week04/\346\216\242\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265/main.go" new file mode 100644 index 00000000..a5c6a81c --- /dev/null +++ "b/week04/\346\216\242\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265/main.go" @@ -0,0 +1,22 @@ +package main + +//74. 搜索二维矩阵 + +//感觉这题与二分也没什么关系 +func searchMatrix(matrix [][]int, target int) bool { + if len(matrix) == 0 || len(matrix[0]) == 0 { + return false + } + colum := len(matrix[0]) - 1 + for row := 0; row < len(matrix); row++ { + if matrix[row][colum] >= target { + for i := 0; i <= colum; i++ { + if matrix[row][i] == target { + return true + } + } + return false + } + } + return false +} diff --git "a/week04/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204/main.go" "b/week04/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204/main.go" new file mode 100644 index 00000000..017f5174 --- /dev/null +++ "b/week04/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204/main.go" @@ -0,0 +1,51 @@ +package main + +import "fmt" + +//33. 搜索旋转排序数组 + +// 给你一个整数数组 nums ,和一个整数 target 。 + +// 该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + +// 请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + +//二分查找 +//输入:nums = [4,5,6,7,0,1,2], target = 0 +// 输出:4 + +//代码有些冗余,但是自己能很好理解 +func search(nums []int, target int) int { + left := 0 + right := len(nums) - 1 + + for left <= right { + + mid := (left + right) / 2 + if nums[mid] == target { + return mid + } + fmt.Println(left, right) + + //按照当前例子,前半段是正常的 后半段是异常 + if nums[mid] >= nums[left] { + if target >= nums[left] && target < nums[mid] { + right = mid - 1 + } else { + left = mid + 1 + } + } else { + if target <= nums[right] && target > nums[mid] { + left = mid + 1 + } else { + right = mid - 1 + } + } + + } + return -1 +} + +func main() { + fmt.Println(search([]int{5, 1, 3}, 5)) +} diff --git "a/week04/\346\237\240\346\252\254\351\205\270\346\211\276\351\233\266/main.go" "b/week04/\346\237\240\346\252\254\351\205\270\346\211\276\351\233\266/main.go" new file mode 100644 index 00000000..6be31534 --- /dev/null +++ "b/week04/\346\237\240\346\252\254\351\205\270\346\211\276\351\233\266/main.go" @@ -0,0 +1,31 @@ +package main + +// 860. 柠檬水找零 + +// 题意一开始误解了,应该是挺简单的题目 +func lemonadeChange(bills []int) bool { + five := 0 + ten := 0 + for _, value := range bills { + if value == 5 { + five++ + } else if value == 10 { + if five >= 1 { + five-- + ten++ + } else { + return false + } + } else if value == 20 { + if five >= 1 && ten >= 1 { + five-- + ten-- + } else if five >= 3 { + five -= 3 + } else { + return false + } + } + } + return true +} diff --git a/week06/221.go b/week06/221.go new file mode 100644 index 00000000..9815979a --- /dev/null +++ b/week06/221.go @@ -0,0 +1,40 @@ +package main + +// 在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 +//子问题 递推公式需要转换一下才能取值 +// 理解 min(上, 左, 左上) + 1 这个好难想到 +//https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-2/ +func maximalSquare(matrix [][]byte) int { + m := len(matrix) + n := len(matrix[0]) + dp := make([][]int, len(matrix)) + maxSide := 0 + for i := 0; i < len(matrix); i++ { + dp[i] = make([]int, len(matrix[i])) + for j := 0; j < len(matrix[i]); j++ { + dp[i][j] = int(matrix[i][j] - '0') + if dp[i][j] == 1 { + maxSide = 1 + } + } + } + + for i := 1; i < m; i++ { + for j := 1; j < n; j++ { + if dp[i][j] == 1 { + dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1 + if dp[i][j] > maxSide { + maxSide = dp[i][j] + } + } + } + } + return maxSide * maxSide +} + +func min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/week06/621.go b/week06/621.go new file mode 100644 index 00000000..5106fbdc --- /dev/null +++ b/week06/621.go @@ -0,0 +1,5 @@ +package main + +func leastInterval(tasks []byte, n int) int { + +} diff --git a/week06/64.go b/week06/64.go new file mode 100644 index 00000000..207089d2 --- /dev/null +++ b/week06/64.go @@ -0,0 +1,41 @@ +package main + +import "fmt" + +// 64. 最小路径和 + +// 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +//自底向上处理 子问题 a[i][j]=min(a[i-1][j],a[i][j-1]) + +func minPathSum(grid [][]int) int { + for i := 0; i < len(grid); i++ { + for j := 0; j < len(grid[i]); j++ { + if i == 0 && j == 0 { + continue + } else if i == 0 { + grid[i][j] = grid[i][j-1] + grid[i][j] + } else if j == 0 { + grid[i][j] = grid[i-1][j] + grid[i][j] + } else { + grid[i][j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1]) + } + } + } + fmt.Println(grid) + return grid[len(grid)-1][len(grid[0])-1] +} + +func min(x, y int) int { + if x < y { + return x + } + return y +} + +func main() { + minPathSum([][]int{ + {1, 2}, + {1, 1}, + }) +} diff --git a/week06/647.go b/week06/647.go new file mode 100644 index 00000000..fad9da07 --- /dev/null +++ b/week06/647.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" +) + +//回文字符串的个数 + +//dp[i][j]=dp[i+1][j-1] 参考dp.png图片 + +func countSubstrings(s string) int { + if s == "" { + return 0 + } + n := len(s) + dp := make([][]bool, n) + for i := 0; i < n; i++ { + dp[i] = make([]bool, n) + } + //初始化dp + result := 0 + // + fmt.Println(dp) + for j := 0; j < n; j++ { + for i := 0; i <= j; i++ { + if i == j { + dp[i][j] = true + result++ + } else if j-i == 1 && s[i] == s[j] { + dp[i][j] = true + result++ + } else if j-i > 1 && s[i] == s[j] && dp[i+1][j-1] { + dp[i][j] = true + result++ + } + } + } + return result +} diff --git a/week06/91.go b/week06/91.go new file mode 100644 index 00000000..2724da1f --- /dev/null +++ b/week06/91.go @@ -0,0 +1,29 @@ +package main + +//寻找子问题,处理。 +// 当s[i] == '0', 若s[i-1]=='1'||'2', 则 dp[i] = dp[i-2] + +// 当s[i-1] == '1', dp[i] = dp[i-1] + dp[i-2] //相当于 跨一步 + 跨两步 + +//最大字母为为26 +// 当s[i-1] == '2', 若s[i]<='6', dp[i] = dp[i-1] + dp[i-2], 否则dp[i]=dp[i-1] + +func numDecodings(s string) int { + if s[0] == '0' { + return 0 + } + pre, cur := 1, 1 + for i := 1; i < len(s); i++ { + tmp := cur + if s[i] == '0' { + if s[i-1] != '1' && s[i-1] != '2' { + return 0 + } + cur = pre + } else if s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6') { + cur += pre + } + pre = tmp + } + return cur +} diff --git a/week06/dp.png b/week06/dp.png new file mode 100644 index 00000000..5b74634d Binary files /dev/null and b/week06/dp.png differ diff --git a/week07/127.go b/week07/127.go new file mode 100644 index 00000000..00be4aed --- /dev/null +++ b/week07/127.go @@ -0,0 +1,73 @@ +package main + +//127 单词接龙 + +// 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + +// 每次转换只能改变一个字母。 +// 转换过程中的中间单词必须是字典中的单词。 + +// 输入: +// beginWord = "hit", +// endWord = "cog", +// wordList = ["hot","dot","dog","lot","log","cog"] + +// 输出: 5 + +// 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 +//单dfs会超时,其实也能理解因为从前到后要换26次 时间复杂度太高了 + +func ladderLength(beginWord string, endWord string, wordList []string) int { + dic := make(map[string]bool) + for _, v := range wordList { + dic[v] = true + } + + if dic[endWord] == false { + return 0 + } + + q1 := []string{beginWord} + q2 := []string{endWord} + step := 0 + + for len(q1) > 0 && len(q2) > 0 { + step++ + + if len(q1) > len(q2) { + q1, q2 = q2, q1 + } + + for _, w := range q1 { + q1 = q1[1:] + + for j := 0; j < len(w); j++ { + for k := 'a'; k <= 'z'; k++ { + tmp := w[:j] + string(k) + w[j+1:] + + if indexOf(q2, tmp) != -1 { + return step + 1 + } + + if dic[tmp] == false { + continue + } + delete(dic, tmp) + q1 = append(q1, tmp) + } + } + } + } + + return 0 +} + +func indexOf(slice []string, item string) int { + for i, _ := range slice { + if slice[i] == item { + return i + } + } + return -1 +} diff --git a/week07/130.go b/week07/130.go new file mode 100644 index 00000000..366e2ff0 --- /dev/null +++ b/week07/130.go @@ -0,0 +1,45 @@ +package main + +import "fmt" + +//被围绕的区域 dfs处理应该更快 这个跟岛屿数量问题应该是一样的意思 +func solve(board [][]byte) { + m := len(board) + if m == 0 { + return + } + n := len(board[0]) + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if isEdge(i, j, m, n) && board[i][j] == 'O' { + dfs(i, j, board) + } + } + } + fmt.Println(board) + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if board[i][j] == 'O' { + board[i][j] = 'X' + } + if board[i][j] == '#' { + board[i][j] = 'O' + } + } + } +} + +func isEdge(i, j, m, n int) bool { + return i == 0 || j == 0 || i == m-1 || j == n-1 +} + +func dfs(i, j int, board [][]byte) { + if i < 0 || j < 0 || i >= len(board)-1 || j >= len(board[0])-1 || board[i][j] == 'X' || board[i][j] == '#' { + return + } + board[i][j] = '#' + dfs(i-1, j, board) + dfs(i+1, j, board) + dfs(i, j-1, board) + dfs(i, j+1, board) +} diff --git a/week07/200.go b/week07/200.go new file mode 100644 index 00000000..71d5cde5 --- /dev/null +++ b/week07/200.go @@ -0,0 +1,104 @@ +package main + +//dfs或者bfs 四联通向量处理 + +//dfs +func numIslands(grid [][]byte) int { + count := 0 + m := len(grid) + n := len(grid[0]) + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if grid[i][j] == '1' { + count++ + dfs(i, j, grid) + } + } + } + return count +} + +func dfs(i, j int, grid [][]byte) { + if i < 0 || j < 0 || i > len(grid) || j > len(grid[0]) || grid[i][j] == '0' { + return + } + grid[i][j] = '0' + dfs(i-1, j, grid) + dfs(i+1, j, grid) + dfs(i, j-1, grid) + dfs(i, j+1, grid) +} + +//并查集处理 +//直接copy前面的代码部分 +type gridUnion struct { + count int + parent []int +} + +//二维数组变一维 index=i*列+j +func constructorGrid(grid [][]byte) *gridUnion { + row := len(grid) + col := len(grid[0]) + count := row * col + u := &gridUnion{parent: make([]int, count)} + for i := 0; i < row; i++ { + for j := 0; j < col; j++ { + u.parent[i*col+j] = i*col + j + if grid[i][j] == '1' { + u.count++ + } + } + } + return u +} + +func (u *gridUnion) find(p int) int { + for p != u.parent[p] { + u.parent[p] = u.parent[u.parent[p]] + p = u.parent[p] + } + return p +} + +func (u *gridUnion) uniton(p, q int) { + rootQ := u.find(q) + rootP := u.find(p) + + if rootP == rootQ { + return + } + u.parent[rootQ] = rootP + u.count-- +} + +func getIndex(i, j, n int) int { + return i*n + j +} + +func numIslandsUnion(grid [][]byte) int { + row := len(grid) + col := len(grid[0]) + unionFind := constructorGrid(grid) + for i := 0; i < row; i++ { + for j := 0; j < col; j++ { + if grid[i][j] == '1' { + if i-1 >= 0 && grid[i-1][j] == '1' { + unionFind.uniton(i*col+j, (i-1)*col+j) + } + if i+1 < row && grid[i+1][j] == '1' { + unionFind.uniton(i*col+j, (i+1)*col+j) + } + if j-1 >= 0 && grid[i][j-1] == '1' { + unionFind.uniton(i*col+j, i*col+(j-1)) + } + if j+1 < col && grid[i][j+1] == '1' { + unionFind.uniton(i*col+j, i*col+(j+1)) + } + //充值为0 + grid[i][j] = '0' + } + } + } + return unionFind.count +} diff --git a/week07/208.go b/week07/208.go new file mode 100644 index 00000000..3d5ddd89 --- /dev/null +++ b/week07/208.go @@ -0,0 +1,46 @@ +package main + +//前缀树 记住模板就好~其他的灵活一点 + +type Trie struct { + isEnd bool + next [26]*Trie +} + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{} +} + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + for _, v := range word { + if this.next[v-'a'] == nil { + this.next[v-'a'] = new(Trie) + } + this = this.next[v-'a'] + } + this.isEnd = true +} + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + for _, v := range word { + if this.next[v-'a'] == nil { + return false + } + this = this.next[v-'a'] + } + return this.isEnd +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + for _, v := range prefix { + if this.next[v-'a'] == nil { + return false + } + this = this.next[v-'a'] + } + return true +} diff --git a/week07/22.go b/week07/22.go new file mode 100644 index 00000000..25220140 --- /dev/null +++ b/week07/22.go @@ -0,0 +1,24 @@ +package main + +func generateParenthesis(n int) []string { + result := new([]string) + + dfs("", 2*n, n, n, result) + + return *result +} +func dfs(buf string, length, left, right int, result *[]string) { + //移除条件,当长度等于2*n的时候,代表当前已经添加完毕 + if len(buf) == length { + *result = append(*result, buf) + return + } + //任意时候都可以 + if left > 0 { + dfs(buf+"(", length, left-1, right, result) + } + + if left < right { + dfs(buf+")", length, left, right-1, result) + } +} diff --git a/week07/36.go b/week07/36.go new file mode 100644 index 00000000..7203e471 --- /dev/null +++ b/week07/36.go @@ -0,0 +1,37 @@ +package main + +//仅仅是判断是否有效 行列小方格 +func isValidSudoku(board [][]byte) bool { + for i := 0; i < 9; i++ { + mp1 := map[byte]bool{} + mp2 := map[byte]bool{} + mp3 := map[byte]bool{} + for j := 0; j < 9; j++ { + // row + if board[i][j] != '.' { + if mp1[board[i][j]] { + return false + } + mp1[board[i][j]] = true + } + // column + if board[j][i] != '.' { + if mp2[board[j][i]] { + return false + } + mp2[board[j][i]] = true + } + // part 这个有点难搞 + row := (i%3)*3 + j%3 + col := (i/3)*3 + j/3 + if board[row][col] != '.' { + if mp3[board[row][col]] { + return false + } + mp3[board[row][col]] = true + } + + } + } + return true +} diff --git a/week07/433.go b/week07/433.go new file mode 100644 index 00000000..7e1e0055 --- /dev/null +++ b/week07/433.go @@ -0,0 +1,44 @@ +package main + +import "fmt" + +//跟单词接龙是一个意思 用bfs +func minMutation(start string, end string, bank []string) int { + dic := make(map[string]bool) + for _, v := range bank { + dic[v] = true + } + if ok := dic[end]; !ok { + return -1 + } + + ds := []string{"A", "C", "G", "T"} + queue := []string{start} + step := 0 + for len(queue) > 0 { + size := len(queue) + for size > 0 { + word := queue[0] + queue = queue[1:] + for j := 0; j < len(word); j++ { + for k := 0; k < len(ds); k++ { + tmp := word[:j] + ds[k] + word[j+1:] + if _, ok := dic[tmp]; ok { + queue = append(queue, tmp) + delete(dic, tmp) + } + if tmp == end { + return step + } + } + } + size-- + step++ + } + + } + return -1 +} +func main() { + fmt.Println(minMutation("AACCGGTT", "AACCGGTA", []string{})) +} diff --git a/week07/547.go b/week07/547.go new file mode 100644 index 00000000..a8d0130e --- /dev/null +++ b/week07/547.go @@ -0,0 +1,52 @@ +package main + +//bfs 或者并查集 +//并查集 constructor(构造函数) find uniton(合并) + +//https://www.bilibili.com/video/BV13t411v7Fs?p=1 讲的很好 +type union struct { + count int + parent []int +} + +func constructor(n int) *union { + parent := make([]int, n) + for i := 0; i < n; i++ { + parent[i] = i + } + return &union{ + parent: parent, + count: n, + } +} + +func (u *union) find(p int) int { + for p != u.parent[p] { + u.parent[p] = u.parent[u.parent[p]] + p = u.parent[p] + } + return p +} + +func (u *union) uniton(p, q int) { + rootQ := u.find(q) + rootP := u.find(p) + + if rootP == rootQ { + return + } + u.parent[rootQ] = rootP + u.count-- +} + +func findCircleNum(M [][]int) int { + union := constructor(len(M)) + for i := 0; i < len(M); i++ { + for j := 0; j < i; j++ { + if M[i][j] == 1 { + union.uniton(i, j) + } + } + } + return union.count +} diff --git a/week07/70.go b/week07/70.go new file mode 100644 index 00000000..fbdf4caa --- /dev/null +++ b/week07/70.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +//dp 动态规划 +//状态转移方程 dp[i]=dp[i-1]+dp[i-2] +func climbStairs(n int) int { + if n <= 2 { + return n + } + dp := make([]int, n+1) + dp[0] = 1 + dp[1] = 1 + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} +func main() { + fmt.Println(climbStairs(3)) +} diff --git a/week07/NOTE.md b/week07/NOTE.md index 50de3041..183ec092 100644 --- a/week07/NOTE.md +++ b/week07/NOTE.md @@ -1 +1,19 @@ -学习笔记 \ No newline at end of file +红黑树跟avl + +avl的四种旋转 和平衡因子的计算 是与树的深度右关系的。-101 +左 +右 +左右 +右左 + + + +--- 做题总结 + +- dfs与bfs写得比以前要熟练了,但是依然不能一气呵成得把题目解答出来。主要失败原因是因为有一些边界值未考虑到,以及做题得遍数还是不够 + +---未做题目 + +单词搜索 II +N 皇后 +解数独 \ No newline at end of file diff --git a/week08/1122.go b/week08/1122.go new file mode 100644 index 00000000..463499d6 --- /dev/null +++ b/week08/1122.go @@ -0,0 +1,34 @@ +package main + +import "sort" + +//日常读不懂题目!!! +// arr2出现 但是arr1未出现元素,升序存放到元素后面 +//新开一块空间存放数据 +// 输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] +// 输出:[2,2,2,1,4,3,3,9,6,7,19] +func relativeSortArray(arr1 []int, arr2 []int) []int { + m := make(map[int][]int) + for _, v := range arr2 { + m[v] = make([]int, 0) + } + var other []int + for _, v := range arr1 { + if l, ok := m[v]; ok { + l = append(l, v) + m[v] = l + } else { + other = append(other, v) + } + } + // 将不在arr2的元素存在另外一个数组中,对这个数组重新排序 + sort.Ints(other) + var res []int + for _, v := range arr2 { + res = append(res, m[v]...) + } + //添加到arr2中 + res = append(res, other...) + + return arr1 +} diff --git a/week08/146.go b/week08/146.go new file mode 100644 index 00000000..abb47861 --- /dev/null +++ b/week08/146.go @@ -0,0 +1,89 @@ +package main + +//实现LRU + +type Node struct { + key int + value int + prev *Node + next *Node +} + +type LRUCache struct { + //记录链表的长度 + size int + //记录map的容量 + capacity int + cache map[int]*Node + head, tail *Node +} + +func Constructor(capacity int) LRUCache { + l := &LRUCache{ + size: 0, + capacity: capacity, + cache: map[int]*Node{}, + head: &Node{key: 0, value: 0}, + tail: &Node{key: 0, value: 0}, + } + l.head.next = l.tail + l.tail.next = l.head + return *l + +} + +func (this *LRUCache) Get(key int) int { + if value, ok := this.cache[key]; ok { + //需要移动当前指针到队头 + this.moveToHead(value) + return value.value + } + return -1 +} + +func (this *LRUCache) moveToHead(node *Node) { + this.removeNode(node) + this.addToHead(node) +} + +func (this *LRUCache) addToHead(node *Node) { + node.prev = this.head + node.next = this.head.next + this.head.next.prev = node + this.head.next = node +} + +func (this *LRUCache) removeNode(node *Node) { + node.prev.next = node.next + node.next.prev = node.prev +} + +func (this *LRUCache) Put(key int, v int) { + //存放节点 + //放在队列头 + //记录当前value + if value, ok := this.cache[key]; ok { + //已经存在就替换 + value.value = v + this.moveToHead(value) + this.size++ + if this.size > this.capacity { + //淘汰一个不长使用的 + node := this.removeTail() + //清理缓存 + delete(this.cache, node.key) + this.size-- + } + } else { + //不存在就创建节点 + node := &Node{key: key, value: v} + this.cache[key] = node + this.addToHead(node) + + } +} +func (this *LRUCache) removeTail() *Node { + node := this.tail.prev + this.removeNode(node) + return node +} diff --git a/week08/191.go b/week08/191.go new file mode 100644 index 00000000..84a6efaf --- /dev/null +++ b/week08/191.go @@ -0,0 +1,11 @@ +package main + +//用位运算 +func hammingWeight(num uint32) int { + sum := 0 + for num > 0 { + num &= num - 1 + sum++ + } + return sum +} diff --git a/week08/231.go b/week08/231.go new file mode 100644 index 00000000..18c37117 --- /dev/null +++ b/week08/231.go @@ -0,0 +1,9 @@ +package main + +// 2的幂 +//给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +//二进制中只能存在1个 1 + +func isPowerOfTwo(n int) bool { + return n&(n-1) == 0 +} diff --git a/week08/242.go b/week08/242.go new file mode 100644 index 00000000..c48a7639 --- /dev/null +++ b/week08/242.go @@ -0,0 +1,24 @@ +package main + +// 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词 + +// 利用hashmap计数即可 +func isAnagram(s string, t string) bool { + mac := make(map[rune]int) + for _, value := range s { + mac[value]++ + } + for _, value := range t { + if temp, ok := mac[value]; ok { + temp = temp - 1 + if temp == 0 { + delete(mac, value) + } else { + mac[value] = temp + } + } else { + return false + } + } + return len(mac) == 0 +} diff --git a/week08/56.go b/week08/56.go new file mode 100644 index 00000000..12bcf9d8 --- /dev/null +++ b/week08/56.go @@ -0,0 +1,31 @@ +package main + +import "sort" + +//因为给定的每个小区间都是升序的,问题就变得很清楚了,首先排序元素, +//然后一次遍历区间的最大值关系,然后决定是否合并 +func merge(intervals [][]int) [][]int { + //排序 + sort.Slice(intervals, func(i, j int) bool { + return intervals[i][0] < intervals[j][0] + }) + res := [][]int{} + prev := intervals[0] + for i := 1; i < len(intervals); i++ { + cur := intervals[i] + if prev[1] < cur[0] { // 没有一点重合 + res = append(res, prev) + prev = cur + } else { // 有重合 + prev[1] = max(prev[1], cur[1]) + } + } + res = append(res, prev) + return res +} +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/week08/NOTE.md b/week08/NOTE.md index 50de3041..60b51a2e 100644 --- a/week08/NOTE.md +++ b/week08/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +双向链表的操作 + +挺有趣的 \ No newline at end of file diff --git a/week09/115.go b/week09/115.go new file mode 100644 index 00000000..1517043e --- /dev/null +++ b/week09/115.go @@ -0,0 +1,18 @@ +package main + +func numDistinct(s string, t string) int { + dp := [1001][1001]int{} + sl, tl := len(s), len(t) + dp[tl][sl] = 1 + for ti := tl; ti >= 0; ti-- { + for si := sl - 1; si >= 0; si-- { + dp[ti][si] = dp[ti][si+1] + if ti == tl { + dp[ti][si] = 1 + } else if t[ti] == s[si] { + dp[ti][si] += dp[ti+1][si+1] + } + } + } + return dp[0][0] +} diff --git a/week09/121.go b/week09/121.go new file mode 100644 index 00000000..baa374b6 --- /dev/null +++ b/week09/121.go @@ -0,0 +1,32 @@ +package main + +import "fmt" + +//转移方程 + +//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]) 不动 买进 +func maxProfit(prices []int) int { + if len(prices) == 0 { + return 0 + } + dp := make([][2]int, len(prices)) + for i := 0; i < len(prices); i++ { + if i == 0 { + dp[i][0] = 0 + dp[i][1] = 0 - prices[i] + continue + } + dp[i][0] = max(dp[i-1][0], dp[i-1][1]+prices[i]) + dp[i][1] = max(dp[i-1][1], -prices[i]) + } + fmt.Println(dp) + return dp[len(prices)-1][0] +} + +func max(x, y int) int { + if x < y { + return y + } + return x +} diff --git a/week09/198.go b/week09/198.go new file mode 100644 index 00000000..ffa41b4c --- /dev/null +++ b/week09/198.go @@ -0,0 +1,21 @@ +package main + +//状态转移方程 + +//dp[i]=max(dp[i-2]+nums[i],dp[i-1]) +func rob(nums []int) int { + if len(nums) == 0 { + return 0 + } + if len(nums) == 1 { + return nums[0] + } + dp := make([]int, len(nums)) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i := 2; i < len(nums); i++ { + dp[i] = max(dp[i-2]+nums[i], dp[i-1]) + } + return dp[len(nums)-1] +} diff --git a/week09/300.go b/week09/300.go new file mode 100644 index 00000000..9242c96c --- /dev/null +++ b/week09/300.go @@ -0,0 +1,27 @@ +package main + +//状态转移方程dp代表长度 +// dp[i]=max(dp[j]+1,dp[i]) + +//n平方的时间复杂度 +func lengthOfLIS(nums []int) int { + if len(nums) == 0 { + return 0 + } + var res int + //初始化 + dp := make([]int, len(nums)) + for i := 0; i < len(nums); i++ { + dp[i] = 1 + } + //处理 + for i := 0; i < len(nums); i++ { + for j := 0; j < i; j++ { + if nums[i] > nums[j] { + dp[i] = max(dp[i], dp[j]+1) + } + } + res = max(res, dp[i]) + } + return res +} diff --git a/week09/32.go b/week09/32.go new file mode 100644 index 00000000..e7b76060 --- /dev/null +++ b/week09/32.go @@ -0,0 +1,34 @@ +package main + +// 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + +//状态转移方程 dp代表数量 + +//s[i]等于右括号的时候 ....) 这时候只需要找前面一个是否属于左括号 或者前面的前面是否已经有左括号 +//紧挨着的左括号 dp[i]=dp[i-1]+2 +//挨着的不是左括号,那就继续往前找 + +//使用栈是最合适的求解,但是在这里顺便练习一下动态规划 +func longestValidParentheses(s string) int { + dp := make([]int, len(s)) + maxAns := 0 + for i := 1; i < len(s); i++ { + if s[i] == ')' { + if s[i]-1 == '(' { + if i >= 2 { + dp[i] = dp[i-2] + 2 + } else { + dp[i] = 2 + } + } else if i-dp[i-1] > 0 && s[i-dp[i-1]-1] == '(' { + if i-dp[i-1] >= 2 { + dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2 + } else { + dp[i] = dp[i-1] + 2 + } + } + maxAns = max(maxAns, dp[i]) + } + } + return maxAns +} diff --git a/week09/62.go b/week09/62.go new file mode 100644 index 00000000..5a17045f --- /dev/null +++ b/week09/62.go @@ -0,0 +1,30 @@ +package main + +import "fmt" + +// 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 + +// 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 + +//dp方程 +//dp[i][j]=dp[i-1][j]+dp[i][j-1] +func uniquePaths(m int, n int) int { + dp := make([][]int, m) + //需要先初始化 + for i := 0; i < m; i++ { + dp[i] = make([]int, n) + } + for i := 0; i < m; i++ { + dp[i][0] = 1 + } + for i := 0; i < n; i++ { + dp[0][i] = 1 + } + fmt.Println(dp) + for i := 1; i < m; i++ { + for j := 1; j < n; j++ { + dp[i][j] = dp[i-1][j] + dp[i][j-1] + } + } + return dp[m-1][n-1] +} diff --git a/week09/63.go b/week09/63.go new file mode 100644 index 00000000..92842004 --- /dev/null +++ b/week09/63.go @@ -0,0 +1,31 @@ +package main + +//dp[i][j]=dp[i-1][j]+dp[i][j-1] +func uniquePathsWithObstacles(obstacleGrid [][]int) int { + m := len(obstacleGrid) + n := len(obstacleGrid[0]) + if m > 0 && n > 0 && obstacleGrid[0][0] == 1 { + return 0 + } + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if i == 0 && j == 0 { + obstacleGrid[i][j] = 1 + continue + } + if obstacleGrid[i][j] == 1 { + obstacleGrid[i][j] = 0 + } else { + if i == 0 { + obstacleGrid[i][j] = obstacleGrid[i][j-1] + } else if j == 0 { + obstacleGrid[i][j] = obstacleGrid[i-1][j] + } else { + obstacleGrid[i][j] = obstacleGrid[i-1][j] + obstacleGrid[i][j-1] + } + } + } + } + return obstacleGrid[m-1][n-1] +} diff --git a/week09/64.go b/week09/64.go new file mode 100644 index 00000000..adc2f57f --- /dev/null +++ b/week09/64.go @@ -0,0 +1,35 @@ +package main + +// 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +// 说明:每次只能向下或者向右移动一步。 + +//状态转移方程 +//dp[i][j]=dp[i][j]+min(dp[i-1][j],dp[i][j-1]) + +//边界值要注意下i:=0;i +func minPathSum(grid [][]int) int { + m := len(grid) + n := len(grid[0]) + for i := 0; i < len(grid); i++ { + for j := 0; j < len(grid[i]); j++ { + if i == 0 && j == 0 { + continue + } else if i == 0 { + grid[i][j] = grid[i][j] + grid[i][j-1] + } else if j == 0 { + grid[i][j] = grid[i-1][j] + grid[i][j-1] + } else { + grid[i][j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1]) + } + } + } + return grid[m-1][n-1] +} + +func min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/week09/70.go b/week09/70.go new file mode 100644 index 00000000..769d4062 --- /dev/null +++ b/week09/70.go @@ -0,0 +1,27 @@ +package main + +//爬楼梯问题 + +//1 2 3 ...可以爬1 2 3阶 +//只能从m[] 数组给的选择 +//爬楼梯的中间不能相等 + +// 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 + +// 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? + +// 注意:给定 n 是一个正整数。 +func climbStairs(n int) int { + var dp []int + dp[0] = 1 + dp[1] = 2 + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//可以爬 1 2 3 +//dp[i] = dp[i-1] + dp[i-2]+dp[i-3] + +//需要数组的情况下 diff --git a/week09/818.go b/week09/818.go new file mode 100644 index 00000000..7d7cbd6a --- /dev/null +++ b/week09/818.go @@ -0,0 +1 @@ +// 818. 赛车 diff --git a/week09/85.go b/week09/85.go new file mode 100644 index 00000000..3757b090 --- /dev/null +++ b/week09/85.go @@ -0,0 +1,13 @@ +package main + +func maximalRectangle(matrix [][]byte) int { + for i := 0; i > len(matrix); i++ { + for j := 0; j < len(matrix[i]); j++ { + if matrix[i][j] == 1 { + + } + + } + } + +} diff --git a/week09/91.go b/week09/91.go new file mode 100644 index 00000000..87b9cd38 --- /dev/null +++ b/week09/91.go @@ -0,0 +1,46 @@ +package main + +import "fmt" + +// 一条包含字母 A-Z 的消息通过以下方式进行了编码: + +// 'A' -> 1 +// 'B' -> 2 +// ... +// 'Z' -> 26 +// 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + +// 题目数据保证答案肯定是一个 32 位的整数。 +//状态转移方程 +//数量 dp +//当前等于0的时候,前缀一定是1或者2 + +// 处理 最开始比较特别所以一定要注意边界值 i>2=2 dp[i]=dp[i-2] dp[i]=1 +//不等于0 dp[i]=dp[i]+dp[i-1] +func numDecodings(s string) int { + if s == "0" { + return 0 + } + if s[0] == '0' { + return 0 + } + dp := make([]int, len(s)) + dp[0] = 1 + for i := 1; i < len(s); i++ { + if s[i-1] == '1' || s[i-1] == '2' && s[i] >= '0' && s[i] <= '6' { + if i >= 2 { + dp[i] = dp[i-2] + } else { + dp[i] = 1 + } + } + if s[i] != '0' { + dp[i] += dp[i-1] + } + } + fmt.Println(dp) + return dp[len(s)-1] +} +func main() { + numDecodings("12") +} diff --git a/week09/NOTE.md b/week09/NOTE.md index 50de3041..0f78c249 100644 --- a/week09/NOTE.md +++ b/week09/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file + + + +不足点 + +dp 不足 + + +现在能解部分的题目,但是所有东西列出来,寻找状态转移方程的时候,还是在没办法最快找到 \ No newline at end of file diff --git "a/week09/\345\255\227\347\254\246\344\270\262/387.go" "b/week09/\345\255\227\347\254\246\344\270\262/387.go" new file mode 100644 index 00000000..f15fdaa1 --- /dev/null +++ "b/week09/\345\255\227\347\254\246\344\270\262/387.go" @@ -0,0 +1,18 @@ +package main + +//利用hash +//或者利用数组 +func firstUniqChar(s string) int { + var arr [26]int + for i, k := range s { + arr[k-'a'] = i + } + for i, k := range s { + if i == arr[k-'a'] { + return i + } else { + arr[k-'a'] = -1 + } + } + return -1 +} diff --git "a/week09/\345\255\227\347\254\246\344\270\262/541.go" "b/week09/\345\255\227\347\254\246\344\270\262/541.go" new file mode 100644 index 00000000..4ff7352d --- /dev/null +++ "b/week09/\345\255\227\347\254\246\344\270\262/541.go" @@ -0,0 +1,171 @@ +package main + +import ( + "fmt" + "strconv" +) + +// 输入: +// beginWord = "hit", +// endWord = "cog", +// wordList = ["hot","dot","dog","lot","log","cog"] + +// 输出: 5 + +// 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 + +//bfs +func ladderLength(beginWord string, endWord string, wordList []string) int { + mac := map[string]int{} + for _, value := range wordList { + mac[value] = 1 + } + if mac[endWord] == 0 { + return 0 + } + var front []string + var end []string + front = append(front, beginWord) + end = append(end, endWord) + count := 0 + for len(front) > 0 && len(end) > 0 { + count++ + if len(front) > len(end) { + front, end = end, front + } + for _, word := range front { + front = front[1:] + for index := range word { + for c := 'a'; c <= 'z'; c++ { + newWord := word[:index] + string(c) + word[index+1:] + if contains(newWord, end) { + fmt.Println(newWord, end) + return count + 1 + } + if mac[newWord] == 0 { + continue + } + delete(mac, newWord) + front = append(front, newWord) + } + } + } + } + return 0 +} + +func contains(key string, result []string) bool { + for _, value := range result { + if value == key { + return true + } + } + return false +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func rightSideView(root *TreeNode) []int { + result := new([]int) + if root == nil { + return *result + } + dfsVies(root, result, 0) + return *result +} + +func dfsVies(root *TreeNode, result *[]int, depth int) { + if root == nil { + return + } + if depth == len(*result) { + *result = append(*result, root.Val) + } + depth++ + //注意当前顺序问题====》为解决退化成链表的形式 + dfsVies(root.Right, result, depth) + + dfsVies(root.Left, result, depth) +} + +var ( + width map[int]int + ans int +) + +func widthOfBinaryTree(root *TreeNode) int { + ans = 0 + width = map[int]int{} + dfsWidth(root, 0, 0) + return ans +} + +func dfsWidth(root *TreeNode, depth, pos int) { + if root == nil { + return + } + if _, ok := width[depth]; !ok { + width[depth] = pos + } + //每一层的宽度 + ans = max(ans, pos-width[depth]+1) + dfsWidth(root.Left, depth+1, 2*pos) + dfsWidth(root.Right, depth+1, 2*pos+1) +} + +func max(x, y int) int { + if x < y { + return y + } + return x +} + +// 给定一个无重复元素的有序整数数组 nums 。 + +// 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。 + +// 列表中的每个区间范围 [a,b] 应该按如下格式输出: + +// "a->b" ,如果 a != b +// "a" ,如果 a == b + +// 输入:nums = [0,1,2,4,5,7] +// 输出:["0->2","4->5","7"] +// 解释:区间范围是: +// [0,2] --> "0->2" +// [4,5] --> "4->5" +// [7,7] --> "7" + +func summaryRanges(nums []int) []string { + var sb []string + var i int + for j := 0; j < len(nums); j++ { + if j+1 == len(nums) || nums[j]+1 != nums[j+1] { + var s string + s = s + strconv.Itoa(nums[i]) + if i != j { + s = s + "->" + strconv.Itoa(nums[j]) + } + sb = append(sb, s) + i = j + 1 + } + } + return sb +} + +func main() { + root := &TreeNode{ + Val: 1, + } + left := &TreeNode{ + Val: 2, + } + root.Left = left + + fmt.Println(rightSideView(root)) +} diff --git a/week10/NOTE.md b/week10/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/week10/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git "a/week10/\346\200\273\347\273\223.md" "b/week10/\346\200\273\347\273\223.md" new file mode 100644 index 00000000..99b7f9bc --- /dev/null +++ "b/week10/\346\200\273\347\273\223.md" @@ -0,0 +1,6 @@ +总体对早已经遗忘的数据结构和算法过了一遍,在群里看到了很多上进的人。 +有天赋的人往往比你更努力。 + +成长 + +眼界拓宽了,看到了更多的算法理解。