-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
yehong
committed
May 25, 2021
1 parent
4a22b72
commit 57f8da3
Showing
13 changed files
with
430 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package week01 | ||
|
||
// 92. 反转链表 II | ||
// 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表 。 | ||
// 示例 1: | ||
// 输入:head = [1,2,3,4,5], left = 2, right = 4 | ||
// 输出:[1,4,3,2,5] | ||
// @lc: https://leetcode-cn.com/problems/reverse-linked-list-ii/ | ||
|
||
// 方法一:找到[left,right]子区间,反转子链表后再拼接 | ||
// 1. 从虚拟头节点走 left-1 步,来到 left 节点的前一个节点 | ||
// 2. 从 pre 再走 right-left+1 步,来到 right 节点(注意此时是right节点,而不是right的前一个 或 后一个节点) | ||
// 3. 切断出一个子链表(截取链表),同第 206 题,反转链表的子区间 | ||
// 4. 接回到原来的链表中 | ||
// 时间复杂度:O(n) | ||
// 空间复杂度:O(1) | ||
func reverseBetween1(head *ListNode, left, right int) *ListNode { | ||
dummy := &ListNode{Val: -1} // 哑结点,链表通用解法 | ||
dummy.Next = head | ||
// 1. 从虚拟头节点走 left-1 步,来到 left 节点的前一个节点 | ||
pre := dummy | ||
for i := 0; i < left-1; i++ { | ||
pre = pre.Next | ||
} | ||
|
||
// 2. 从 pre 再走 right-left+1 步,来到 right 节点 | ||
rightNode := pre | ||
for i := 0; i < right-left+1; i++ { | ||
rightNode = rightNode.Next | ||
} | ||
|
||
// 3. 切断出一个子链表(截取链表),并反转 | ||
leftNode := pre.Next // 子链表的头结点 | ||
cur := rightNode.Next // right的下一个节点,先保存起来,便于第4步拼接 | ||
|
||
// 切断 | ||
pre.Next = nil | ||
rightNode.Next = nil | ||
// 反转子链表 | ||
reverseList(leftNode) | ||
|
||
// 4. 接回到原来的链表中 | ||
pre.Next = rightNode | ||
leftNode.Next = cur | ||
|
||
return dummy.Next | ||
} | ||
|
||
// reverseList 反转单链表 | ||
// 双指针,先保存下一个节点为tmp,然后把cur反转(cur.Next指向前一个),最后再同时更新pre和cur | ||
func reverseList(head *ListNode) { | ||
var pre *ListNode = nil | ||
cur := head | ||
for cur != nil { | ||
tmp := cur.Next // 先保存下一个节点,因为马上要断开 | ||
cur.Next = pre // 反转操作 | ||
pre = cur // pre指针后移 | ||
cur = tmp // cur指针后移 | ||
} | ||
} | ||
|
||
// 方法二:头部插入法,方法一的问题在于:如果left=1,right=n(链表长度)时,会遍历2次链表 | ||
// 1. 从虚拟头节点走 left-1 步,来到 left 节点的前一个节点 | ||
// 2. 从 left-1..right 依次将当前节点插入到 子区间的头部,也就是拼接到 pre后面 | ||
// 第二步的具体步骤: | ||
// 2.1. pre指针永远不动,指向的是left 的前一个节点 | ||
// 2.2. cur指针指向 待反转区域的第一个节点 left | ||
// 2.3. next指针永远指向 cur的下一个节点,循环过程中,cur 变化后 next 会随着变化 | ||
// @ref: https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/fan-zhuan-lian-biao-ii-by-leetcode-solut-teyq/ | ||
// 时间复杂度:O(n) | ||
// 空间复杂度:O(1) | ||
func reverseBetween2(head *ListNode, left, right int) *ListNode { | ||
dummy := &ListNode{Val: -1} // 哑结点,链表通用解法 | ||
dummy.Next = head | ||
|
||
// 1. 从虚拟头节点走 left-1 步,来到 left 节点的前一个节点 | ||
pre := dummy | ||
for i := 0; i < left-1; i++ { | ||
pre = pre.Next | ||
} | ||
|
||
cur := pre.Next | ||
for i := 0; i < right-left; i++ { | ||
next := cur.Next | ||
cur.Next = next.Next | ||
next.Next = pre.Next | ||
pre.Next = next | ||
} | ||
return dummy.Next | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package week08 | ||
|
||
// 208. 实现 Trie (前缀树) | ||
// Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。 | ||
// 请你实现 Trie 类: | ||
// Trie() 初始化前缀树对象。 | ||
// void insert(String word) 向前缀树中插入字符串 word。 | ||
// boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。 | ||
// boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。 | ||
|
||
// Trie是便于word插入和查找的数据结构 | ||
type Trie struct { | ||
children [26]*Trie | ||
isLeaf bool | ||
} | ||
|
||
func Constructor() *Trie { | ||
return &Trie{} | ||
} | ||
|
||
func (t *Trie) Insert(word string) { | ||
node := t | ||
for _, char := range word { | ||
char -= 'a' // ASCII code | ||
if node.children[char] == nil { | ||
node.children[char] = &Trie{} | ||
} | ||
node = node.children[char] // 一层层进入子节点 | ||
} | ||
node.isLeaf = true // 最终的子节点 | ||
} | ||
|
||
func (t *Trie) SearchPrefix(prefix string) *Trie { | ||
node := t | ||
for _, char := range prefix { | ||
char -= 'a' | ||
if node.children[char] == nil { | ||
return nil | ||
} | ||
node = node.children[char] | ||
} | ||
return node | ||
} | ||
|
||
func (t *Trie) Search(word string) bool { | ||
node := t.SearchPrefix(word) | ||
return node != nil && node.isLeaf | ||
} | ||
|
||
func (t *Trie) StartsWith(prefix string) bool { | ||
return t.SearchPrefix(prefix) != nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package week08 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// run: go test -v -run Test_trie | ||
func Test_trie(t *testing.T) { | ||
assert := assert.New(t) | ||
trie := Constructor() | ||
|
||
trie.Insert("apple") | ||
assert.True(trie.Search("apple"), "Search apple") | ||
assert.False(trie.Search("app"), "Search app") | ||
assert.True(trie.StartsWith("app"), "StartsWith app") | ||
|
||
trie.Insert("app") | ||
assert.True(trie.Search("app"), "Search app") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package week08 | ||
|
||
// 212. 单词搜索 II | ||
// 给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。 | ||
// 单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 | ||
// @lc: https://leetcode-cn.com/problems/word-search-ii/ | ||
func findWords(board [][]byte, words []string) []string { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package week08 | ||
|
||
// 695. 岛屿的最大面积 | ||
// 给定一个包含了一些 0 和 1 的非空二维数组 grid 。 | ||
// 一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。 | ||
// 找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。) | ||
// @lc: https://leetcode-cn.com/problems/max-area-of-island/ | ||
|
||
// dfs递归 | ||
func maxAreaOfIsland(grid [][]int) int { | ||
// 合法性判断 | ||
if len(grid) == 0 || len(grid[0]) == 0 { | ||
return 0 | ||
} | ||
|
||
// 行、列数 | ||
rows, cols := len(grid), len(grid[0]) | ||
// 上下左右 与当前位置的offset | ||
directions := [][2]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}} | ||
// 判断当前位置是否在网格内 | ||
inGrid := func(i, j int) bool { | ||
return i >= 0 && i < rows && j >= 0 && j < cols | ||
} | ||
|
||
var dfsMarking func(i, j int) int | ||
dfsMarking = func(i, j int) int { | ||
// terminator, 跳出网格 或 当前位置不是陆地 '1',即被mark过了 | ||
if !inGrid(i, j) || 1 != grid[i][j] { | ||
return 0 | ||
} | ||
|
||
// mark 为'2',且递归把他的上下左右已经子子孙孙都mark | ||
grid[i][j] = 2 | ||
area := 1 | ||
for _, direct := range directions { | ||
area += dfsMarking(i+direct[0], j+direct[1]) | ||
} | ||
return area | ||
} | ||
|
||
max := func(a, b int) int { | ||
if a > b { | ||
return a | ||
} | ||
return b | ||
} | ||
// 遍历网格,求 maxArea | ||
var res int | ||
for i := 0; i < rows; i++ { | ||
for j := 0; j < cols; j++ { | ||
res = max(res, dfsMarking(i, j)) | ||
} | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package week08 | ||
|
||
// 79. 单词搜索 | ||
// 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 | ||
// 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 | ||
// 示例 1: | ||
// 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" | ||
// 输出:true | ||
// @lc: https://leetcode-cn.com/problems/word-search/ | ||
|
||
// DFS+回溯 | ||
func exist(board [][]byte, word string) bool { | ||
// 分别为 当前位置与 上、下、左、右 的offset | ||
directions := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}} | ||
if len(board) == 0 || len(board[0]) == 0 { | ||
return false | ||
} | ||
|
||
// 初始化,rows,cols,visited | ||
rows, cols := len(board), len(board[0]) | ||
visited := make([][]bool, rows) | ||
for i := 0; i < rows; i++ { | ||
visited[i] = make([]bool, cols) | ||
} | ||
|
||
// 坐标是否在 board 内,防止越界 | ||
inArea := func(x, y int) bool { | ||
return x >= 0 && x < rows && y >= 0 && y < cols | ||
} | ||
|
||
// dfs marking func | ||
n := len(word) | ||
var dfs func(int, int, int) bool | ||
dfs = func(i, j, begin int) bool { | ||
if begin == n-1 { // terminator | ||
return board[i][j] == word[begin] | ||
} | ||
if board[i][j] == word[begin] { | ||
visited[i][j] = true // marking | ||
for _, direction := range directions { // process | ||
x := i + direction[0] | ||
y := j + direction[1] | ||
if inArea(x, y) && !visited[x][y] { | ||
if dfs(x, y, begin+1) { | ||
return true | ||
} | ||
} | ||
} | ||
visited[i][j] = false // revert | ||
} | ||
return false | ||
} | ||
|
||
// dfs marking | ||
for i := 0; i < rows; i++ { | ||
for j := 0; j < cols; j++ { | ||
if dfs(i, j, 0) { | ||
return true | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// AC过了,懒得写单测了 | ||
// @lc https://leetcode-cn.com/problems/word-search/solution/79-dan-ci-sou-suo-dfshui-su-golangban-be-ekcn/ |
Oops, something went wrong.