From a243718760698e7b6f39a34fbefff762970decb4 Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Tue, 30 Aug 2022 16:09:19 +0800 Subject: [PATCH 01/10] day1/31 --- ...75\346\225\260\347\232\204\346\240\210.go" | 60 ++++++++++++++++++ ...36\347\216\260\351\230\237\345\210\227.go" | 63 +++++++++++++++++++ ...76\350\241\250\345\256\236\347\216\260.go" | 35 +++++++++++ 3 files changed, 158 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\351\223\276\350\241\250\345\256\236\347\216\260.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.go" "b/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.go" new file mode 100644 index 0000000..fb7dd34 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.go" @@ -0,0 +1,60 @@ +// 题目链接:https://leetcode.cn/problems/bao-han-minhan-shu-de-zhan-lcof/ +// 思路:建立辅助栈,与存储数据的栈大小相同,在向栈中存数据时,辅助栈同时存入一个数字 +// 该辅助栈入栈元素的序列是一个非严格递增序列 +// 如果该数据小于辅助栈栈顶元素,则辅助栈存入该数据,否则辅助栈还存入一个辅助栈的栈顶元素。 +//(如果是存入第一个元素,辅助栈直接入栈即可,无比较操作) + +package main + +type MinStack struct { + nums []int //储存栈 + min []int //辅助储存栈,存储最小值 +} + +/** initialize your data structure here. */ +// 为解决命名冲突,这里函数名后+“2”,在LeetCode需删除 +func Constructor2() MinStack { + return MinStack{ + []int{}, + []int{}, + } +} + +// 入栈时,存储栈直接入栈 +// 对辅助栈,若栈长度为0,直接入栈 +// 否则,与栈顶元素进行比较,若大于栈顶元素,入栈,否则,辅助栈再次存入栈顶元素 +func (this *MinStack) Push(x int) { + this.nums=append(this.nums,x) + if len(this.min)==0{ + this.min=append(this.min,x) + }else if this.min[len(this.min)-1] 0{ + x := this.stack1[len(this.stack1)-1] + this.stack2 = append(this.stack2,x) + this.stack1 = this.stack1[:len(this.stack1)-1] + } + } + // stack2出栈的元素即为队首元素 + if len(this.stack2) > 0{ + res := this.stack2[len(this.stack2)-1] + this.stack2 = this.stack2[:len(this.stack2)-1] + return res + } + // 若stack2长度仍为0,说明队列为空,返回-1 + return -1 +} + + +/** + * Your CQueue object will be instantiated and called as such: + * obj := Constructor(); + * obj.AppendTail(value); + * param_2 := obj.DeleteHead(); + */ \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\351\223\276\350\241\250\345\256\236\347\216\260.go" "b/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\351\223\276\350\241\250\345\256\236\347\216\260.go" new file mode 100644 index 0000000..7ecbf5a --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day1_\346\240\210\344\270\216\351\230\237\345\210\227\357\274\210\347\256\200\345\215\225\357\274\211/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\351\223\276\350\241\250\345\256\236\347\216\260.go" @@ -0,0 +1,35 @@ +// 题目解析在 用两个栈实现队列.go +// 本文件为 用链表实现的栈 来 实现队列 +// 为解决命名冲突,本文件结构体与函数名后+1 +package main + +import "container/list" + +type CQueue1 struct { + stack1, stack2 *list.List +} + +func Constructor1() CQueue1 { + return CQueue1{ + stack1: list.New(), + stack2: list.New(), + } +} + +func (this *CQueue1) AppendTail1(value int) { + this.stack1.PushBack(value) +} + +func (this *CQueue1) DeleteHead1() int { + if this.stack2.Len() == 0 { + for this.stack1.Len() > 0 { + this.stack2.PushBack(this.stack1.Remove(this.stack1.Back())) + } + } + if this.stack2.Len() != 0 { + e := this.stack2.Back() + this.stack2.Remove(e) + return e.Value.(int) + } + return -1 +} \ No newline at end of file From 23363f8c02faec7e0d517e81e127535e02e3ac39 Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Wed, 31 Aug 2022 20:41:50 +0800 Subject: [PATCH 02/10] update day2/31 --- ...23\345\215\260\351\223\276\350\241\250.go" | 54 ++++++++++ ...15\350\275\254\351\223\276\350\241\250.go" | 59 +++++++++++ ...50\347\232\204\345\244\215\345\210\266.go" | 100 ++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\217\215\350\275\254\351\223\276\350\241\250.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.go" "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.go" new file mode 100644 index 0000000..39e0423 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.go" @@ -0,0 +1,54 @@ +// 题目链接:https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/?plan=lcof&plan_progress=klczit3 +// day2/31 +// 第二天主题为:链表(简单) +// 包含三道题目: +// 剑指offer06.从尾到头打印链表 +// 剑指offer30.反转链表 +// 剑指offer35.复杂链表的复制 + +// 解题思路:从尾到头打印链表,最后返回整数切片,也就是说,链表头节点的值为切片最后的元素 +// 而链表尾结点的值为切片第一个元素 +// 与链表的遍历结合,很容易想到先进后出的解题策略 +// 说到”先进后出“,那必然会用到栈,先用栈来解题 +// 从头到尾遍历链表,将节点依次入栈 +// 遍历结束后,在从栈顶逐个输出节点的值至整数切片即可 + +package main + + +//Definition for singly-linked list. +type ListNode struct { + Val int + Next *ListNode +} + + +func reversePrint(head *ListNode) []int { + stack := []*ListNode{} + res := []int{} + if head == nil{ + return []int{} + } + for head != nil{ + stack = append(stack,head) + head = head.Next + } + for len(stack) > 0{ + res = append(res,stack[len(stack)-1].Val) + stack = stack[:len(stack)-1] + } + return res +} + +// 法2:递归在本质上是一个栈结构,针对本题,我们也可以使用递归来实现 +// 容易想到,要实现反过来输出链表,每当我们访问到一个节点时,要将 +// 当前节点的值放在返回切片的末尾,先递归输出其之后的节点, +// 当访问到当前的节点为空节点时,返回空切片即可 +// 利用系统栈,实现了从尾到头打印链表 +// 为避免命名冲突,此函数名后添加了后缀 ”_recursion“ +func reversePrint_recursion(head *ListNode) []int { + if head == nil{ + return []int{} + } + return append(reversePrint(head.Next),head.Val) +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\217\215\350\275\254\351\223\276\350\241\250.go" "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\217\215\350\275\254\351\223\276\350\241\250.go" new file mode 100644 index 0000000..cd5e124 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\217\215\350\275\254\351\223\276\350\241\250.go" @@ -0,0 +1,59 @@ +// 题目链接:https://leetcode.cn/problems/fan-zhuan-lian-biao-lcof/ + +// 解题思路:本题最通俗的解法为迭代,从头到尾遍历链表,不断更改当前节点的Next域 +// 我们需要事先引入一个空节点,第一次迭代时,头结点指向pre,之后不断更新 +// 更改Next域前,要记录当前节点的Next域指向的节点,防止链表出现断裂 +// 做链表相关题目时,一定要谨防链表断裂的情况出现 +// 此题的另一个要注意的点是代码的鲁棒性 +// 表头指针为 null 或者整个链表只有一个节点时,我们要保证程序依旧能正常运行。 + +package main + +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ + +// 关于Go语言中关于空节点的初始化需要格外注意,本题中对应pre的初始化 +// 我最初的写法是 pre:=*ListNode{},报错: indirect of leetcode.ListNode{} +// ListNode{}的间接无效,不确定该如何翻译 +// 若 pre 初始化为 nil,报错:use of untyped nil (solution.go) +// pre:=new(ListNode) 也是不可以的,最后输出的切片结果会多一个0元素 +// 正确写法为 var pre *ListNode,此时pre为空节点,无零值,值为nil +// 好吧,这块是我对GO理解存在问题,为什么 *ListNode{}不可以,我需要再思考一下 +func reverseList(head *ListNode) *ListNode { + var pre *ListNode + cur := head + for cur != nil{ + pnext := cur.Next + cur.Next = pre + pre,cur = cur,pnext + } + // 遍历结束后,cur指向nil节点,pre指向原先链表的尾结点 + return pre +} + +// 法2:递归 +// 理解:如果链表长度为2,结构为:a->b->nil 想要反转链表,可以用 +// a.Next.Next=a +// a.Next=nil +// return b +// 这三行代码实现,明白这个,那递归就好理解了 +// 假设链表长度大于2,当前正在处理b节点,b往后的节点已经完成反转 +// 我们希望b指向a,则 a.Next.Next=a +// 若当目前处理节点为空,或其Next域为空时,返回该节点,即新链表的头结点 +// 为避免命名冲突,本函数名后添加了后缀 ”_recursion“ +func reverseList_recrusion(head *ListNode) *ListNode { + if head == nil || head.Next == nil{ + return head + } + newhead := reverseList(head.Next) + head.Next.Next = head + // 虽然这行代码实质上只为原链表的头结点服务,但是仍然不可缺少 + // 若无下面这行代码,链表有可能会形成环 + head.Next = nil + return newhead +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.go" "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.go" new file mode 100644 index 0000000..1a9c33e --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day2_\351\223\276\350\241\250(\347\256\200\345\215\225)/\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.go" @@ -0,0 +1,100 @@ +//题目链接:https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/?envType=study-plan&id=lcof + +// 感觉这道题题目描述地不够清晰,可以查看主站138题的题目描述 +// 刚看到这个题目我是有些困惑的,遍历原链表,然后逐个生成新节点不就可以了吗,思考过后,才发现不是这样的 +// 如果没有 random域,确实可以在遍历的同时创建节点,设当前遍历到的节点为 cur,对 Next 指向的节点 pnext +// 先创建Val相同,Next为空的节点next,然后将当前节点 cur 指向next,然后 cur=next,遍历完成后即可完成复制 +// 但本题中 Node 节点包含了 Random 域,Random 指向的节点位置是随机的,可能该节点还未创建,无法进行指向 +// 本题的难点就在于构建新链表节点的 Random 域。 +// 所以,我们需要进行两次遍历,第一次创建节点,给 Val 域复制,第二次遍历给 Next 域 和 Random 域 进行指向。 +// 还有一个问题,如何保存第一次遍历创建的节点呢?哈希表应该是第一个浮现在脑海中的数据结构,键为原链表节点,值为新创建的原节点对应的节点。 + +// 上面讲的有些啰嗦了,下面看具体实现,参考自题解: +// https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/jian-zhi-offer-35-fu-za-lian-biao-de-fu-zhi-ha-xi-/ +// 利用哈希表的查询特点,第一次遍历构建原链表节点和新链表节对应节点的键值对映射关系, +// 第二次遍历构建新链表各节点的 Next 与 Random 指向即可。 +//1. 若头结点head为空,直接返回 head +//2. 构建哈希表 record +//3. 复制链表,进行第一次遍历,构建新节点,Next和Random域均为空 +//4. 第二次遍历,所有节点已创建完成,根据record进行Next和Random域的指向 +//5. 返回新链表的头结点record[head] +package main + + +//Definition for a Node. +type Node struct { + Val int + Next *Node + Random *Node +} + + +func copyRandomList(head *Node) *Node { + if head == nil{ + return head + } + record := map[*Node]*Node{} + cur := head + for cur != nil{ + node := Node{cur.Val,nil,nil} + record[cur] = &node + cur = cur.Next + } + cur = head + for cur != nil{ + if cur.Next != nil{ + record[cur].Next = record[cur.Next] + } + if cur.Random != nil{ + record[cur].Random = record[cur.Random] + } + cur = cur.Next + } + return record[head] +} + + +// 上述解法为哈希表,是一种通俗的解法,下面看一种非常巧妙的解法 +// 法2:拼接+拆分 +// 这里建议大家多画图去理解这种解法 +// 考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表 +// 如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。 +//算法流程: +//1. 复制各节点,构建拼接链表:设原链表为 a->b->...,构建的拼接链表为:a->a'->b->b'->... +//2. 构建新链表各节点的random指向:当访问原节点cur的随机指向节点cur.random时,对应新节点cur.next的随机指向节点为cur.random.next 。 +//3. 拆分原/新链表:设置pre/cur分别指向原/新链表头节点,遍历执行pre.next=pre.next.next和cur.next=cur.next.next将两链表拆分开。 +//4. 返回新链表的头节点 res 即可。 + +// 为避免命名冲突,此函数名后添加了后缀 ”_2“ +func copyRandomList_2(head *Node) *Node { + if head == nil{ + return head + } + cur := head + for cur != nil{ + temp := &Node{cur.Val,nil,nil} + temp.Next = cur.Next + cur.Next = temp + cur = temp.Next + // 同 cur = cur.Next.Next + } + cur = head + for cur != nil{ + if cur.Random != nil{ + cur.Next.Random = cur.Random.Next + } + cur = cur.Next.Next + } + cur,res := head.Next,head.Next + pre := head + for cur.Next != nil{ + pre.Next = pre.Next.Next + cur.Next = cur.Next.Next + pre = pre.Next + cur = cur.Next + } + // 处理原链表尾结点 + pre.Next = nil + // 返回新链表头结点 + return res +} \ No newline at end of file From 294376129aec31617ca01d25e33869e039cf0d46 Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Thu, 1 Sep 2022 19:44:00 +0800 Subject: [PATCH 03/10] update day3/31 --- ...54\345\255\227\347\254\246\344\270\262.go" | 89 +++++++++++++++++++ ...77\346\215\242\347\251\272\346\240\274.go" | 81 +++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day3_\345\255\227\347\254\246\344\270\262(\347\256\200\345\215\225)/\345\267\246\346\227\213\350\275\254\345\255\227\347\254\246\344\270\262.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day3_\345\255\227\347\254\246\344\270\262(\347\256\200\345\215\225)/\346\233\277\346\215\242\347\251\272\346\240\274.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day3_\345\255\227\347\254\246\344\270\262(\347\256\200\345\215\225)/\345\267\246\346\227\213\350\275\254\345\255\227\347\254\246\344\270\262.go" "b/LeetCode/\345\211\221\346\214\207offer/day3_\345\255\227\347\254\246\344\270\262(\347\256\200\345\215\225)/\345\267\246\346\227\213\350\275\254\345\255\227\347\254\246\344\270\262.go" new file mode 100644 index 0000000..5a21d1f --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day3_\345\255\227\347\254\246\344\270\262(\347\256\200\345\215\225)/\345\267\246\346\227\213\350\275\254\345\255\227\347\254\246\344\270\262.go" @@ -0,0 +1,89 @@ +// 题目链接:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/?plan=lcof&plan_progress=klczit3 +// day3/31 +// 第 3 天主题为:字符串(简单) +// 包含两道题目: +// 剑指offer05.替换空格 +// 剑指offer58-II.左旋转字符串 + + +// 此题题解前三个方法参考自:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/solution/mian-shi-ti-58-ii-zuo-xuan-zhuan-zi-fu-chuan-qie-p/ +// 解题思路:设字符串s的长度为n,首先,很容易想到,s左旋n位还是原本的字符串,我们只需要左旋k%n次即可。 +// 此题解法较多,请耐心观看 +package main + +// 方法1:也是最通俗的解法,字符串切片进行拼接 +func reverseLeftWords(s string, n int) string { + n = n % len(s) + return s[n:] + s[:n] +} + +// 如果面试不允许对字符串进行切片,那我们可以对列表进行遍历,然后进行拼接,记为方法2: +// 先遍历从下标n到末尾的字符串元素,加入返回的rune切片res,然后遍历下标0-n,添加至res。最后返回将res转换为string返回即可 +// 为避免命名冲突,此函数名添加后缀 “_2" +func reverseLeftWords_2(s string, n int) string { + res := make([]rune,len(s)) + n = n % len(s) + k := 0 + for i:=n;i=0;i--{ + if s[i]==' '{ + res[j-2] = '%' + res[j-1] = '2' + res[j] = '0' + j -= 3 + } else { + res[j] = rune(s[i]) + j -- + } + } + return string(res) +} + +// 若遍历方向改为从前往后,同理 +// 为避免命名冲突,此函数名添加后缀 “_2" +func replaceSpace_2(s string) string { + nums := 0 + for _,x := range s{ + if x == ' '{ + nums ++ + } + } + m := len(s) + 2 * nums + res := make([]rune,m) + j := 0 + for i:=0;i Date: Fri, 2 Sep 2022 21:24:01 +0800 Subject: [PATCH 04/10] update day4/31 --- ...61\347\232\204\346\225\260\345\255\227.go" | 49 +++++++++ ...5\346\211\276\346\225\260\345\255\227I.go" | 78 +++++++++++++++ ...15\347\232\204\346\225\260\345\255\227.go" | 99 +++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/0~n-1\344\270\255\347\274\272\345\244\261\347\232\204\346\225\260\345\255\227.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/0~n-1\344\270\255\347\274\272\345\244\261\347\232\204\346\225\260\345\255\227.go" "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/0~n-1\344\270\255\347\274\272\345\244\261\347\232\204\346\225\260\345\255\227.go" new file mode 100644 index 0000000..6a79f00 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/0~n-1\344\270\255\347\274\272\345\244\261\347\232\204\346\225\260\345\255\227.go" @@ -0,0 +1,49 @@ +// 题目链接:https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/ +// day4/31 +// 第 4 天主题为:查找算法(简单) +// 包含三道题目: +// 剑指offer03.数组中重复的数字 +// 剑指offer53-I.旋转数组的最小数字 +// 剑指offer50.第一个只出现一次的字符 + +// 解题思路:题目出现有序,优先考虑二分 +// 此题的通俗解法为,遍历数组 +// 当nums[i]不等于下标i时,说明从下标i开始,之后的元素值均为下标值+1,返回下标i即可。 +package main + +func missingNumber(nums []int) int { + for i:=0;i>1 + //优先考虑两种极端情况 + if mid==0 && nums[mid]!=mid{ + return mid + } else if mid==n-1 && nums[mid]==mid{ + return mid+1 + } else if nums[mid]!=mid && nums[mid-1]==mid-1{ + return mid + } else if nums[mid] != mid{ + right = mid - 1 + } else { + left = mid + 1 + } + } + return -1 +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.go" "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.go" new file mode 100644 index 0000000..7840cf2 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.go" @@ -0,0 +1,78 @@ +//题目链接:https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/ + +package main + +// 最通俗的解法,遍历数组,统计target出现的次数 +// 但这样的话完全没用到题目中数组是排序的 这个条件 +// 显然,本题想要考察二分查找算法! +// 看到有序数组就应该第一时间想到二分查找 +func search(nums []int, target int) int { + n := len(nums) + ans := 0 + for i := 0;i < n;i++{ + if nums[i] == target{ + ans += 1 + } + } + return ans +} + +// 方法2:两次二分查找 +// 统计一个数字在排序数组中出现的次数,那我们只需要知道其在数组中第一次和最后一次出现的下标 +// 设为 left 和 right,出现次数即为:right-left+1 +// 函数 first_equal_search 和 last_equal_search 分别用于查找数字第一次和最后一次出现的位置下标。 +// 实现上述两个函数时,网上有很多花里花哨的写法,如果去死记硬背,没过几天就会全部忘光 +// 下面我的写法非常好理解 +// 为避免命名冲突,次函数名添加后缀 “_2” +func search_2(nums []int, target int) int { + left := first_equal_search(nums,target) + right := last_equal_search(nums,target) + // 若出现次数为 0,需额外处理 + if left == -1{ + return 0 + } + return right-left+1 +} + +func first_equal_search(nums []int,target int) int{ + n := len(nums) + left,right := 0,n-1 + for left <= right{ + mid := left + (right-left)>>1 + if mid==0 && nums[mid]==target{ + return mid + } else if mid>0 && nums[mid]==target && nums[mid-1]!=target{ + return mid + } else if nums[mid] < target{ + left = mid + 1 + } else if nums[mid] > target{ + right = mid - 1 + } else { + // 此种情况说明 mid 指向元素为众多与target相等元素的其中一个 + // 而且不在起始点,我们要找第一个,所以移动右指针 + right = mid -1 + } + } + return -1 +} + +func last_equal_search(nums []int,target int) int{ + n := len(nums) + left,right := 0,n-1 + for left <= right{ + mid := left + (right-left)>>1 + if mid==n-1 && nums[mid]==target{ + return mid + } else if mid target{ + right = mid - 1 + } else { + // 与找第一个相等的元素同理,不在最后一个,所以移动左指针 + left = mid + 1 + } + } + return -1 +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.go" "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.go" new file mode 100644 index 0000000..3cc74b7 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day4_\346\237\245\346\211\276\347\256\227\346\263\225(\347\256\200\345\215\225)/\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.go" @@ -0,0 +1,99 @@ +// 题目链接:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/ + +package main + +// 解题思路:本题最通俗的解法为哈希表,用哈希表记录nums数组中元素是否出现过, +// 若出现过,返回该元素即可。 +func findRepeatNumber(nums []int) int { + record := map[int]int{} + for _,num := range nums{ + if record[num] > 0{ + return num + } + record[num] ++ + } + return -1 +} + +// 方法2:设计哈希表 +// 哈希表解法的时间与空间复杂度均为O(n),该方法没有用到题目给的数字范围条件,所以应该思考下如何做改进 +// 试想下如何降低复杂度,对长度为n的数组,其中所有数字都在0~n-1范围内,而0~n-1又是长度为n的数组的所有下标索引。我们刚才方法是将其值放入哈希表 +// 而现在我们给定数组的长度为n,0~n-1刚好可以对应数组索引,让我们有一种将数组设计为哈希表的思路: +// 对数组进行遍历,设当前遍历到的的数字值为 x,则将索引为 x 对应的数字打标记,若之后遍历到某元素后,打标记过程中发现该元素已打标记,说明该数字已出现过,返回即可。 +// 现在要做的就是设计标记,标记为取负值,流程如下: +// 一次遍历数组中元素,设当前元素值为num,它可能已经被打了标记,我们取用其原数x=abs(num) +// 如果 nums[x] < 0,说明 x 已经出现过,返回 x 即可,否则,打标记,nums[x] = -nums[x] +// 但还存在一个问题,就是0取负还是0,我没想到太好的解决方案,就用了最朴素的方法,单独处理0。 +// 处理流程如下:初始化0的下标为 zero_index,遍历数组,得到0的下标zero_index,然后第二次遍历数组,若数组元素值为 zero_index的元素个数大于1,说明该元素重复,返回0的下标即可。 +// 这样的解题思路来自LeetCode41题:缺失的第一个正数 +// 算法核心在于将输入数组设计为哈希表,另外,我在此题的题解部分还没有看人有人用类似的方案解此题 +// 在进行此操作前,请务必与面试官进行交流,询问是否可以修改输入数组,确定可以的话,再用此方案。 +// 为避免命名冲突,次函数名添加后缀 “_2" +func findRepeatNumber_2(nums []int) int { + // 先处理0的情况 + // m为nums中0的下标出现的次数,zero_index为0的下标初始值 + m := 0 + zero_index := -1 + // 第一次遍历得到0的下标 + for i:=0;i 1{ + return zero_index + } + // 将输入数组设计为哈希表 + for _,num := range nums{ + x := abs(num) + // nums[x]<0,说明x元素此前出现过 + if nums[x] < 0{ + return x + } + // 若未出现过,打标记 + nums[x] = -nums[x] + } + return -1 +} + +func abs(num int) int { + if num < 0{ + return -num + } + return num +} + + +// 方法3:原地交换 次题解方法来自:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/solution/mian-shi-ti-03-shu-zu-zhong-zhong-fu-de-shu-zi-yua/ +// 长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内 。 此说明含义:数组元素的 索引 和 值 是 一对多 的关系。 +// 因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = i)。因而,就能通过索引映射对应的值,起到与字典等价的作用。 +// 遍历中,第一次遇到数字 x 时,将其交换至索引 x 处;而当第二次遇到数字 x 时,一定有 nums[x] = x,此时即可得到一组重复数字。。 +// 算法流程: +// 遍历数组 nums,设索引初始值为 i = 0 : +// 若 nums[i] = i: 说明此数字已在对应索引位置,无需交换,因此跳过; +// 若 nums[nums[i]] = nums[i]: 代表索引nums[i]处和索引i处的元素值都 nums[i],即找到一组重复值,返回此值 nums[i]; +// 否则,交换索引为i和nums[i]的元素值,将此数字交换至对应索引位置。 +// 若遍历完毕尚未返回,则返回 -1 。 +// 为避免命名冲突,次函数名添加后缀 “_3" +func findRepeatNumber_3(nums []int) int { + i := 0 + for i < len(nums){ + // 交换 nums[i]至索引i出后才进行下一索引处的交换 + if nums[i] == i{ + i ++ + continue + } + if nums[nums[i]] == nums[i]{ + return nums[i] + } + nums[nums[i]],nums[i] = nums[i],nums[nums[i]] + } + return -1 +} \ No newline at end of file From baed255b1efff75e1c738aff730aaae5900ab08d Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Sat, 3 Sep 2022 22:17:12 +0800 Subject: [PATCH 05/10] update day5/31 --- ...55\347\232\204\346\237\245\346\211\276.go" | 59 +++++++++++++++++++ ...00\345\260\217\346\225\260\345\255\227.go" | 47 +++++++++++++++ ...41\347\232\204\345\255\227\347\254\246.go" | 22 +++++++ 3 files changed, 128 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.go" "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.go" new file mode 100644 index 0000000..038a789 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.go" @@ -0,0 +1,59 @@ +// 题目链接:https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/?plan=lcof&plan_progress=klczit3 +// day5/31 +// 第 5 天主题为:查找算法(中等) +// 包含三道题目: +// 剑指offer04.二维数组中的查找 +// 剑指offer11.旋转数组的最小数字 +// 剑指offer50.第一个只出现一次的字符 + +// 通俗解法就是遍历二维数组的每个元素,查看是否存在值等于target的元素,若存在,返回 true,否则,false。 +// 但这完全没用到题目所给的递增条件,直接pass,就不附代码。 +// 当我们需要解决一个复杂的问题时,一个很有效的办法就是从一个具体的问题入手,通过分析简单具体的例子,试图寻找普遍的规律。 +// 利用下题目所给条件,每一行从左到右递增,每一列从上到下递增。这道题,找一下规律。 +// 如果我们先选取数组右上角的数字,则该数字左侧元素小于其值,下方元素大于其值,类似二叉搜索树。 +// 如果 target > 右上角数字的数值,则剔除第一行,第二行最后一个元素作为最右上角的数字, +// 同样的做法,每次移动,消除一行或者一列元素,直到找到目标值 target,或者 查找范围为空(即 target 不存在于二维数组中)。 +package main + +func findNumberIn2DArray(matrix [][]int, target int) bool { + if len(matrix)==0 || len(matrix[0]) == 0{ + return false + } + m,n := len(matrix),len(matrix[0]) + i,j := 0,n-1 + for matrix[i][j] != target{ + if matrix[i][j] > target{ + j -- + } else { + i ++ + } + if i>=m || j <0{ + return false + } + } + return true +} + +// 另外,本题从左下角分析也可以,道理是一样的,下述代码为从左下角元素开始的“二分” +// 为避免函数命名冲突,次函数名添加后缀 “_2” +func findNumberIn2DArray_2(matrix [][]int, target int) bool { + if len(matrix)==0 || len(matrix[0]) == 0{ + return false + } + m,n := len(matrix),len(matrix[0]) + i,j := m-1,0 + for matrix[i][j] != target{ + if matrix[i][j] > target{ + i -- + } else { + j ++ + } + if i<0 || j >= n{ + return false + } + } + return true +} + +// 本题考点:考察应聘者对二维数组的理解及编程能力,还考察应聘者分析问题的能力,当发现问题比较复杂时,是否能通过具体的例子找出其中的规律,是能够解决这个问题的关键所在。 +// 本题只要从一个具体的二维数组的右上角开始分析,就能找到规律所在,从而找到解决问题的突破口。 \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.go" "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.go" new file mode 100644 index 0000000..223471c --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.go" @@ -0,0 +1,47 @@ +//题目链接:https://leetcode.cn/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/?plan=lcof&plan_progress=klczit3 + +package main + +// 尽管题目描述看起来并不复杂,但本题是一道实实在在的困难题 +// 我个人在这道题上花费时间超过5h,现在有时候还是会绕进去 +// + +// 二分思想很简单,细节是魔鬼!各种边界处理问题 +// Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky... ----Knuth +// +// 解题思路:二分查找,参照题解 [旋转数组的最小数字 - 旋转数组的最小数字 - 力扣(LeetCode)](https://leetcode.cn/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-by-leetcode-s/) +// 强烈建议观看官方题解,有图片作参考会好理解一些 +// 左右边界 left 和 right 初始化为 0 和 len(numbers)-1,假设最小值出现在 mid 位置,我们考虑数组中的最后一个元素 x: +// 在最小值右侧的元素,它们的值一定都小于等于 x;而在最小值左侧的元素,它们的值一定都大于等于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。 + +// 将中间元素 number[mid] 和 numbers[right] 作比较,可能会出现以下三种情况:(为什么拿这两个位置的数字作比较,题解没有说,但这绝对不是简简单单就能想到的,一定是做了推理,或者经验所得) +//1. numbers[mid] < numbers[right],说明 numbers[mid] 是最小值右侧的元素(也可能就是numbers[mid]),因此我们忽略当前整个搜索区间的右半部分。right=mid +//2. number[mid] > numbers[right],说明最小值在 mid 右侧,我们忽略二分查找区间的左半部分。left = mid + 1 +//3. numbers[mid] = numbers[right],在这种情况下,我们无法确定最小值在mid的左侧还是右侧,但我们能确定的是,由于它们值相同,所以无论 numbers[high]是不是最小值, +// 其都有一个替代值 numbers[mid],因此我们可以忽略当前搜索区间的右端点。right-- +// 最终 left 与 right 落于同一位置,即最小值所在的索引。 +// +// 在这里,谈一下个人的想法:看题解,有时候我们觉得看懂了,但关掉题解,写代码的时候就忘了该怎么做,或者隔几天就忘了,很多时候就是因为你只看到了题解部分, +// 没有看到题解之外的,作者是如何从题目所给条件推导到题解这一步的,就比如,我第一次看这道题的官方题解时,就没有思考过为什么查找的条件是 left < right,而不是 left <= right, +// 还有,为什么比较的是 mid 元素 和 right 元素,而不是 left 元素,这些题解都没有说,如果自己不去想清楚,那就做不到对这道题的完美把控。 +// 当然,现在我明白了,left=right 时,我们已经找到了最小值所在的索引。 +// 这种能力的获得不是一蹴而就的,而是慢慢获取的。我也在练习的过程中... + + + +func minArray(numbers []int) int { + low := 0 + high := len(numbers) - 1 + for low < high { + pivot := low + (high - low) / 2 + if numbers[pivot] < numbers[high] { + high = pivot + } else if numbers[pivot] > numbers[high] { + low = pivot + 1 + } else { + high-- + } + } + return numbers[low] +} + diff --git "a/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.go" "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.go" new file mode 100644 index 0000000..7d1a58d --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day5_\346\237\245\346\211\276\347\256\227\346\263\225(\344\270\255\347\255\211)/\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.go" @@ -0,0 +1,22 @@ +// 题目链接:https://leetcode.cn/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/ + +package main + + +// 解题思路:两次遍历字符串,第一次遍历的过程中,用哈希表存储每个字符出现的次数, +// 第二次遍历字符串时,哈希表查看当前字符出现次数,若哈希表值为1,返回该字符。 +func firstUniqChar(s string) byte { + if len(s) == 0{ + return ' ' + } + record := map[rune]int{} + for _,x := range s{ + record[x] ++ + } + for _,x := range s{ + if record[x] == 1{ + return byte(x) + } + } + return ' ' +} \ No newline at end of file From 12d0b5e7a774f3dbde9422874fa476c6b1303062 Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Sun, 4 Sep 2022 19:59:41 +0800 Subject: [PATCH 06/10] update day6/31 --- ...60\344\272\214\345\217\211\346\240\221.go" | 48 ++++++++++++ ...\344\272\214\345\217\211\346\240\221II.go" | 50 +++++++++++++ ...344\272\214\345\217\211\346\240\221III.go" | 74 +++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.go" "b/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.go" new file mode 100644 index 0000000..5452782 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.go" @@ -0,0 +1,48 @@ +// 题目链接:https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/ +// day6/31 +// 第 6 天主题为:搜素与回溯算法(简单) +// 包含三道题目: +// 剑指offer32-I.从上到下打印二叉树 +// 剑指offer32-II.从上到下打印二叉树II +// 剑指offer32-III.从上到下打印二叉树III + +// 本题题解参考自:https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/solution/mian-shi-ti-32-i-cong-shang-dao-xia-da-yin-er-ch-4/ +// 解题思路:从上到下打印二叉树,也就是二叉树的层序遍历,考察 BFS,BFS通常借助队列的先入先出特性来实现。 +//算法流程: +//1. 特例处理: 当树的根节点为空,则直接返回空切片 []int{} ; +//2. 初始化: 打印结果列表 res:=make([]int,0) ,包含根节点的队列 q:=[]*TreeNode{root}; +//3. BFS 循环: 当队列 queue 为空时跳出; +// 1. 出队: 队首元素出队,记为 node; +// 2. 打印: 将 node.val 添加至列表 res 尾部; +// 3. 添加子节点: 若 node 的左(右)子节点不为空,则将左(右)子节点加入队列 queue ; +//4. 返回值: 返回打印结果列表 res 即可。 +package main + + + +// Definition for a binary tree node. +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func levelOrder(root *TreeNode) []int { + if root==nil{ + return []int{} + } + res := []int{} + q := []*TreeNode{root} + for len(q)!=0{ + cur := q[0] + if cur.Left != nil{ + q=append(q,cur.Left) + } + if cur.Right != nil{ + q = append(q,cur.Right) + } + res = append(res,cur.Val) + q = q[1:] + } + return res +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II.go" "b/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II.go" new file mode 100644 index 0000000..193284b --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day6_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II.go" @@ -0,0 +1,50 @@ +// 题目链接:https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/?envType=study-plan&id=lcof + + +package main + +// 解题思路:本质还是考察层序遍历,我们依旧使用队列来实现。 +// 将每层遍历到的节点放在列表中。首先,获取当前q的长度,即当前层节点的数目 n,然后依次访问队列 q 的前 n 个节点, +// 两步操作: +// 1. 将节点 val 添加到当前层的切片中; +// 2. 若当前节点存在孩子节点,按顺序将其添加至列表 q +// 最后,q = q[n:],删除列表中已经访问过的当前层节点,若 q 非空,下一次循环进入下一层节点的处理。 + +//算法流程:(算法流程来自题解:https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/solution/mian-shi-ti-32-ii-cong-shang-dao-xia-da-yin-er-c-5/) +// 写的很系统,值得学习 +//1. 特例处理: 当根节点为空,则返回空切片 []int{} ; +//2. 初始化: 打印结果列表 res:=[]int{} ,包含根节点的队列 queue:=[]*TreeNode{root} ; +//3. BFS 循环: 当队列 queue 为空时跳出; +// 1. 新建一个临时列表 tmp ,用于存储当前层打印结果; +// 2. 当前层打印循环: 循环次数为当前层节点数(即队列 queue 长度); +// 1. 出队: 队首元素出队,记为 node; +// 2. 打印: 将 node.val 添加至 tmp 尾部; +// 3. 添加子节点: 若 node 的左(右)子节点不为空,则将左(右)子节点加入队列 queue ; +// 3. 将当前层结果 tmp 添加入 res 。 +//4. 返回值: 返回打印结果列表 res 即可。 + +// 为避免函数命名冲突,次函数名添加后缀 “_2” +func levelOrder_2(root *TreeNode) [][]int { + if root == nil{ + return [][]int{} + } + res := [][]int{} + q := []*TreeNode{root} + for len(q) != 0{ + n := len(q) + temp := []int{} + for i:=0;i=0;i--{ + temp = append(temp,q[i].Val) + } + } + order ++ + q = q[n:] + res = append(res,temp) + } + return res +} + + +// 然后看了下官方的操作,挺不错的,先按照第二版从上到下打印二叉树的思路解题, +// 最后向返回数组添加某一层遍历结果时,先将该层遍历结果进行翻转,简单易懂。 +// 为避免函数命名冲突,次函数名添加后缀 “_4” +func levelOrder_4(root *TreeNode) (ans [][]int) { + if root == nil { + return + } + queue := []*TreeNode{root} + for level := 0; len(queue) > 0; level++ { + vals := []int{} + q := queue + queue = nil + for _, node := range q { + vals = append(vals, node.Val) + if node.Left != nil { + queue = append(queue, node.Left) + } + if node.Right != nil { + queue = append(queue, node.Right) + } + } + // 本质上和层序遍历一样,我们只需要把奇数层的元素翻转即可 + if level%2 == 1 { + for i, n := 0, len(vals); i < n/2; i++ { + vals[i], vals[n-1-i] = vals[n-1-i], vals[i] + } + } + ans = append(ans, vals) + } + return +} From 526849f8de0267c824a06d3acfbbac0098c5b3d2 Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Mon, 5 Sep 2022 21:51:17 +0800 Subject: [PATCH 07/10] update day7/31 --- ...21\347\232\204\351\225\234\345\203\217.go" | 92 +++++++++++++++++++ ...04\344\272\214\345\217\211\346\240\221.go" | 36 ++++++++ ...04\345\255\220\347\273\223\346\236\204.go" | 60 ++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.go" "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.go" new file mode 100644 index 0000000..988aedb --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.go" @@ -0,0 +1,92 @@ +// 题目链接:https://leetcode.cn/problems/er-cha-shu-de-jing-xiang-lcof/?envType=study-plan&id=lcof +// day7/31 +// 第 7 天主题为:搜索与回溯算法(简单),与前一天主题相同 +// 包含三道题目: +// 剑指offer26.树的子结构 +// 剑指offer27.二叉树的镜像 +// 剑指offer28.对称的二叉树 + + +package main + + +// Definition for a binary tree node. +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +// 解题思路:观察例子可以发现,镜像 就是 每个节点的左右子树进行翻转。所以,两步完成本题: +//1. 遍历二叉树保存所有节点(前中后序遍历都可以),用节点的指针类型切片保存; +//2. 遍历切片,交换其左右子节点 node.Left,node.Right = node.Right,node.Left +func mirrorTree(root *TreeNode) *TreeNode { + nodes := []*TreeNode{} + var preorder func(root *TreeNode) + preorder = func(root *TreeNode){ + if root == nil{ + return + } + nodes = append(nodes,root) + if root.Left != nil{ + preorder(root.Left) + } + if root.Right != nil{ + preorder(root.Right) + } + } + preorder(root) + for _,node := range nodes{ + node.Left,node.Right = node.Right,node.Left + } + return root +} + +// 上面这种解法的时间空间复杂度均为 O(n) +// 我们也可以在遍历的过程中交换节点的左右子节点,省去 nodes 切片占用的内存空间,但这本质上并不会降低时间和空间复杂度, +// 因为我们在对二叉树进行遍历的过程中,调用了系统栈,系统需要使用 O(n) 大小的栈空间。 +// 前序遍历的过程中交换左右子节点 +// 为避免函数命名冲突,次函数名添加后缀 “_2” +func mirrorTree_2(root *TreeNode) *TreeNode { + var preorder func(root *TreeNode) + preorder = func(root *TreeNode){ + if root == nil{ + return + } + root.Left,root.Right = root.Right,root.Left + if root.Left != nil{ + preorder(root.Left) + } + if root.Right != nil{ + preorder(root.Right) + } + } + preorder(root) + return root +} + + +// 另外,在LeetCode题解区我还看到了有人用层序遍历的方式解题,本质上和上面两种思路是一样的,就是选择了另一种遍历二叉树的方式, +// 交换左右子节点的核心操作无任何变化,代码开头的判断 root 节点是否为空不可省略,因为 q 初始化默认加入root节点,若该节点为空,后续代码会出错。 +// 为避免函数命名冲突,次函数名添加后缀 “_3” +func mirrorTree_3(root *TreeNode) *TreeNode { + if root == nil{ + return root + } + q := []*TreeNode{root} + for len(q) != 0{ + node := q[0] + node.Left,node.Right = node.Right,node.Left + if node.Left != nil{ + q = append(q,node.Left) + } + if node.Right != nil{ + q = append(q,node.Right) + } + q = q[1:] + } + return root +} + + +// 二叉树的定义就是递归的,所以做二叉树的题目一定要有递归的想法,有思路后开始着手写代码,不要在脑海中模拟太多层的递归,否则很容易绕进去。 \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.go" "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.go" new file mode 100644 index 0000000..75eadd8 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.go" @@ -0,0 +1,36 @@ +// 题目链接:https://leetcode.cn/problems/dui-cheng-de-er-cha-shu-lcof/?envType=study-plan&id=lcof + +package main + + +// 解题思路:如果二叉树只有一个根节点,那其必然是对称的,本题主要是判断节点的左右子树是否对称。 +// +// 判断左右子树是否对称,若两子树根节点均为空,说明对称,若某子树为空而另一颗子树不为空,说明不对称,两子树根节点值不相等的话也必定不对称吗,否则,对称,之后递归地判断 +//- 左子树的左子树 与 右子树的右子树 是否对称 +//- 左子树的右子树 与 右子树的左子树 是否对称 +// 两者均对称时,说明该左右子树对称;否则,不对称。 + +func isSymmetric(root *TreeNode) bool { + // 根节点为空,对称 + if root == nil{ + return true + } + var sym func(x,y *TreeNode) bool + // 递归判断左右子树是否对称 + sym = func(x,y *TreeNode) bool { + // 两者均为空说明对称 + if x == nil && y == nil{ + return true + // 其中某一子树为空,而另一子树不为空,不对称 + } else if x == nil || y == nil{ + return false + } + // 两者根节点值不相等时也不对称 + if x.Val != y.Val{ + return false + } + // 递归判断x的左右子树 与 y 的右左子树是否对称 + return sym(x.Left,y.Right) && sym(x.Right,y.Left) + } + return sym(root.Left,root.Right) +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.go" "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.go" new file mode 100644 index 0000000..23aeb56 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day7_\346\220\234\347\264\242\344\270\216\345\233\236\346\272\257\347\256\227\346\263\225(\347\256\200\345\215\225)2/\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.go" @@ -0,0 +1,60 @@ +// 题目链接:https://leetcode.cn/problems/shu-de-zi-jie-gou-lcof/ + +package main + + +// 此题解参考自:https://leetcode.cn/problems/shu-de-zi-jie-gou-lcof/solution/mian-shi-ti-26-shu-de-zi-jie-gou-xian-xu-bian-li-p/ +// 若树 B 是 A 的子结构,则 A 子结构的根节点可能是 A 中任意一个节点,我们判断 B 是否为 A 的子结构,就需要遍历 A 的所有节点, +// 然后判断是否有某节点 以 该节点为 根节点的子树包含(有点绕,其实就是,若 A 与 B 根节点相同, B 是否为 A 的子结构, +// 但当 B 为空的时候,B 必为 A 的子结构)。 +// 名词规定:树 A 的根节点记作 节点 A,树 B 的根节点称为 节点 B 。 +// recur(A, B)函数,用于判断树 A 中以 A为根节点的子结构是否包含树 B +//终止条件: +//- 当节点 B 为空:说明树 B 已匹配完成(越过叶子节点),因此返回 true ; +//- 当节点 A 为空:说明已经越过树 A 叶子节点(而 B 节点非空),即匹配失败,返回 false ; +//- 当节点 A 和 B 的值不同:说明匹配失败,返回 false ; +//返回值: +//- 判断 A 和 B 的左子节点是否相等,即 recur(A.left, B.left) ; +//- 判断 A 和 B 的右子节点是否相等,即 recur(A.right, B.right) ; +//两者取逻辑与后返回。 +// 特例处理:当 树 A 为空 或 树 B 为空时,直接返回 false(对应题目中的约定:空树不是任意一个树的子结构) 。 +// 之后我们对 A 作遍历(前中后序都可以),对其中每个节点与 B 进行 recur 判断,若存在 true 结果,返回最终的 true;若全为 false,说明 B 不是 A 的子结构,返回 false。 +func isSubStructure(A *TreeNode, B *TreeNode) bool { + if A == nil || B == nil{ + return false + } + nodes := []*TreeNode{} + // 对树的遍历,这里我采用前序遍历 + // 使用 中序遍历、后序遍历 or 层序遍历都是可以的 + var perorder func(root *TreeNode) + perorder = func(root *TreeNode){ + if root == nil{ + return + } + nodes = append(nodes,root) + if root.Left != nil{ + perorder(root.Left) + } + if root.Right != nil{ + perorder(root.Right) + } + } + perorder(A) + // 判断B是否为以为根节点的子树的在子结构 + var sub func(A,B *TreeNode) bool + sub = func(A,B *TreeNode) bool{ + if B == nil{ + return true + } + if A == nil || A.Val != B.Val { + return false + } + return sub(A.Left,B.Left) && sub(A.Right,B.Right) + } + for _,node := range nodes{ + if sub(node,B){ + return true + } + } + return false +} \ No newline at end of file From 63efa9f29b2d9bccbfa7e5b4ecc2d65c03593f9f Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Tue, 6 Sep 2022 19:48:25 +0800 Subject: [PATCH 08/10] update day8/31 --- ...43\345\245\221\346\225\260\345\210\227.go" | 51 +++++++++++++++++++ ...00\345\244\247\345\210\251\346\266\246.go" | 51 +++++++++++++++++++ ...60\351\230\266\351\227\256\351\242\230.go" | 43 ++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\350\202\241\347\245\250\347\232\204\346\234\200\345\244\247\345\210\251\346\266\246.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.go" "b/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.go" new file mode 100644 index 0000000..813a9c3 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.go" @@ -0,0 +1,51 @@ +// 题目链接:https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof/?envType=study-plan&id=lcof +// day7/31 +// 第 7 天主题为:搜索与回溯算法(简单),与前一天主题相同 +// 包含三道题目: +// 剑指offer10-I.斐波那契数列 +// 剑指offer10-II.青蛙跳台阶问题 +// 剑指offer63.股票的最大利润 + +//关于函数命名冲突的问题,从今天的题解开始,就不再额外标注了 +//我一般通过函数名添加后缀的方式解决 + +package main + +import "math" + +//解题思路:最基础的动态规划问题,题目已经给出状态转移方程,或者可以直接理解为 递归,一个阶段只有一个状态 +//动态规划三步: +//1. 确定dp数组及下标含义:dp[i] 代表 F(i),要求第 n 个斐波那契数,则 dp 数组长度为 n; +//1. 数组初始化:题目已给出,dp[0]=0,dp[1]=1; +//2. 状态转移方程:题目已给出,i>=2时,dp[i] = dp[i-1]+dp[i-2]。 +//最终返回 dp[n-1] 即可 + +func fib(n int) int { + if n <= 1{ + return n + } + x := int(math.Pow(10,9)) + 7 + dp := make([]int,n+1) + dp[0],dp[1] = 0,1 + for i:=2;i 0{ + res = max(res,prices[j]-prices[i]) + } + } + } + return res +} + + +//方法2:一次遍历 +//遍历股票价格的过程中,维护一个股票最小价格,若当前遍历到的价格小于该最小价格,则更新最小价格,否则,更新最大利润。 +//为避免函数命名冲突,次函数名添加后缀 “_2” +func maxProfit_2(prices []int) int { + n := len(prices) + if n == 0{ + return 0 + } + min_price := prices[0] + res := 0 + for i:=1;i y{ + return x + } + return y +} + +//这道题和动态规划有关系吗?我觉得关系不大吧,用递推更加合适一些。 +//主要是场景过于简单,只需要维护一个最小价格,每个阶段只有一个状态,且每个阶段的状态与之前阶段均无关。 \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.go" "b/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.go" new file mode 100644 index 0000000..e158bba --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day8_\345\212\250\346\200\201\350\247\204\345\210\222(\347\256\200\345\215\225)/\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.go" @@ -0,0 +1,43 @@ +//题目链接:https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/ + +package main + +import "math" + + +//本质上和斐波那契数列一样,区别在于 dp 数组初始化不同。 +//跳到第 n 级台阶,我们可以从第 n-1 个台阶跳上去,也可以从 n-2 个台阶跳上去,跳法,即为跳到 n-1 级台阶 和 跳到 n-2 级台阶的跳法之和。 +//动态规划三步: +//1. 确定dp数组及下表含义:dp[i] 代表跳到第 i 级台阶的跳法数量,求跳到第 n 级台阶的跳法数量,dp[0]情况特殊,则 dp 数组长度设为 n+1; +//2. dp 数组初始化:由题意可知,dp[0]=1,dp[1]=1,dp[2]=2 +//3. 状态转移方程:当 i > 2 时,dp[i] = dp[i-1] + dp[i-2] +//最终,返回 dp[n] 即可。 +func numWays(n int) int { + if n <= 1{ + return 1 + } + x := int(math.Pow(10,9)+7) + 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]) % x + } + return dp[n] +} + +//由于每个阶段的状态只与前两个状态有关,所以我们可以用滚动数组代替 dp 数组解题, +//将空间复杂度从 O(n) 降低至 O(1)。 +func numWays_2(n int) int { + if n <= 1{ + return 1 + } + x := int(math.Pow(10,9)+7) + a,b := 1,1 + var res int + for i:=2;i<=n;i++{ + res = (a+b) % x + a,b = b,res + } + return res +} \ No newline at end of file From 4011a211749fa1bc6f0d57e047e3093d43c1f26a Mon Sep 17 00:00:00 2001 From: Obsession-kai <237434765@qq.com> Date: Wed, 7 Sep 2022 16:22:51 +0800 Subject: [PATCH 09/10] update day9/31 --- ...00\345\244\247\344\273\267\345\200\274.go" | 51 +++++++++++++++++++ ...04\346\234\200\345\244\247\345\222\214.go" | 20 ++++++++ 2 files changed, 71 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.go" "b/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.go" new file mode 100644 index 0000000..cd6bcb3 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.go" @@ -0,0 +1,51 @@ +// 题目链接:https://leetcode.cn/problems/li-wu-de-zui-da-jie-zhi-lcof/?envType=study-plan&id=lcof +// day9/31 +// 第 9 天主题为:动态规划(中等) +// 包含两道题目: +// 剑指offer42.连续子数组的最大和 +// 剑指offer47.礼物的最大价值 + +package main + +//经典二维dp,在每个网格的位置有两个选择,向右 或 向下走,当前网格可获得的最大礼物价值, +//就只能从其上面的格子或左边的格子 的最大礼物价值 加上当前格子的礼物价值 得到,回溯到起始节点,容易想到用 dp 解题。 +//动态规划三步骤: +//1. 确定dp数组大小及下标含义:dp[i][j] 代表 从棋盘左上角走到 (i,j) 下标位置可以获得的礼物最大价值, +// 则 len(dp) = len(grid),len(dp[0])=len(grid[0]),即 大小与给定棋盘大小相等; +//2. dp数组初始化:(一般情况下初始第一行和第一列)网格(0,0)为起始位置,dp[0][0] 没有别的选择,dp[0][0] = grid[0][0] +// 因为计算当前网格的最大礼物价值,需要知道其上方和左方网格的最大礼物价值,所以我们要初始化第一行和第一列的 dp 数组元素,防止越界情况的发生; +//3. 状态转移方程:i>1 且 j>1 时:dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + grid[i][j] +// +//最后返回 dp[m-1][n-1] 即可。 + + +func maxValue(grid [][]int) int { + if len(grid)==0 || len(grid[0])==0{ + return 0 + } + m,n := len(grid),len(grid[0]) + dp := make([][]int,m) + for i:=0;i y{ + return x + } + return y +} \ No newline at end of file diff --git "a/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.go" "b/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.go" new file mode 100644 index 0000000..0d161c1 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day9_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)/\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.go" @@ -0,0 +1,20 @@ +// 题目链接:https://leetcode.cn/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/?envType=study-plan&id=lcof +package main + +//简单的一维 dp 入门题目 +//动态规划三步: +//1. 确定dp数组大小及下标含义:dp[i] 代表以下标 i 为最后元素的子数组的最大值,dp 数组长度与给定数组 nums 长度相同。 +//2. dp 数组初始化:每个单独元素都是一个子数组,初始化 dp[0] = nums[0] +//3. 状态转移方程:从下标 1 开始,dp[i] = max(nums[i],nums[i]+dp[i-1]),若 dp[i-1]>0,说明以下标 i 截止的子数组的最大和要包含之前元素,包含多少呢?dp[i-1] 已经处理完了,我们只需要相加即可。 +// 最终需返回 dp 数组的最大值 +func maxSubArray(nums []int) int { + n := len(nums) + dp := make([]int,n) + dp[0] = nums[0] + res := nums[0] + for i:=1;i Date: Thu, 8 Sep 2022 22:28:55 +0800 Subject: [PATCH 10/10] update day10/31 --- ...20\345\255\227\347\254\246\344\270\262.go" | 52 +++++++++++++++++++ ...20\345\255\227\347\254\246\344\270\262.go" | 36 +++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day10_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)2/\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.go" create mode 100644 "LeetCode/\345\211\221\346\214\207offer/day10_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)2/\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.go" diff --git "a/LeetCode/\345\211\221\346\214\207offer/day10_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)2/\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.go" "b/LeetCode/\345\211\221\346\214\207offer/day10_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)2/\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.go" new file mode 100644 index 0000000..fa36960 --- /dev/null +++ "b/LeetCode/\345\211\221\346\214\207offer/day10_\345\212\250\346\200\201\350\247\204\345\210\222(\344\270\255\347\255\211)2/\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.go" @@ -0,0 +1,52 @@ +// 题目链接:https://leetcode.cn/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/?envType=study-plan&id=lcof +// day10/31 +// 第 10 天主题为:动态规划(中等) +// 包含两道题目: +// 剑指offer46.把数字翻译成字符串 +// 剑指offer48.最长不含重复字符的子字符串 +package main + +import "strconv" + +//比较明显的动态规划题目,设 dp[i]代表s[:i+1]的翻译方法数目,dp[i] 明显依赖于 dp[i-1] 与 dp[i-2],类似于斐波那契数是吧, +//本题有点不一样的地方在于 dp[i]=dp[i-1]+dp[i-2] 是有条件的 +//- 当 s[i-1] 与 s[i] 组成的数字小于 25 时,s[i] 可以与 s[i-1] 组合翻译,也可以分开翻译,dp[i]=dp[i-1]+dp[i-2], +//- 否则 s[i] 与 s[i-1] 无法组合翻译,只能单独翻译,dp[i] = dp[i-1] + +//动态规划三步骤: +//- 确定dp数组大小及下标含义:dp[i] 代表 s[:i+1] 的翻译方法数目,len(dp)=len(string(num)) +//- dp 数组初始化:dp[0]对应s[0],单个字符只有一种翻译方法,dp[0]=1,当 s[:2] 小于26 且 s[i]!=0 时,dp[1]=2,否则 dp[1]=1 +//- 状态转移方程:从下标 2 开始遍历,x = strconv.Atoi(s[i-1:i+1]),并且判断 s[i-1] 是否为 0 +//- 若 x < 26 且 s[i-1]!= 0,dp[i]=dp[i-1]+dp[i-2],s[i] 可以与 s[i-1] 组合翻译,也可以单独翻译 +//- 否则,dp[i] = dp[i-1],s[i] 只能单独翻译,s[:i+1] 的翻译方法数目依赖于 s[:i] +// 最后,返回 dp[n-1] 即可。 + +//有一点需要注意,在状态转移方程那里一定要判断 s[i-1] 是否为 0,因为 “01”只能翻译为 “ab”,不能翻译成 “a", +//我第一次做这道题的时候就是忘记判断 s[i-1]是否为0,导致没有ac,刚才做的时候,又在这个地方跌到坑里了,有了再一再二,不会有再三再四了。 +func translateNum(num int) int { + s := strconv.Itoa(num) + n := len(string(s)) + if n == 0{ + return 0 + } + dp := make([]int,n) + dp[0] = 1 + x,_ := strconv.Atoi(s[:2]) + zero,_ := strconv.Atoi(string(s[0])) + if x < 26 && zero != 0{ + dp[1] = 2 + } else { + dp[1] = 1 + } + for i:=2;i start{ + start = record[x] + } else { + res = max(res,i-start) + } + record[x] = i + } + return res +} + +func max(x,y int) int { + if x > y{ + return x + } + return y +} \ No newline at end of file