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 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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 +}