diff --git a/combination-sum/invidam.go.md b/combination-sum/invidam.go.md new file mode 100644 index 000000000..3479a6de9 --- /dev/null +++ b/combination-sum/invidam.go.md @@ -0,0 +1,35 @@ +# Complexity +- Time complexity: $O(N^t)$ + - `target`의 크기 t와 `candiates`의 크기 N에 대하여, t만큼의 재귀호출이 연속적으로 일어날 수 있고 각 함수에서 배열 순회 비용 N이 발생할 수 있다. + +- Space complexity: $O(N^t)$ + - `target`의 크기 t와 `candiates`의 크기 N에 대하여, 백트래킹에서 만들 수 있는 모든 경우의 수 만큼 `ret`이 적재될 수 있다. + +# Code +```go +func combinationSum(candidates []int, target int) [][]int { + sort.Ints(candidates) + + var combination func(candidates []int, target int) [][]int + combination = func(candidates []int, target int) [][]int { + if target < 0 { + return nil + } + if target == 0 { + return [][]int{{}} + } + + ret := make([][]int, 0) + for i, c := range candidates { + items := combination(candidates[i:], target-c) + for _, item := range items { + ret = append(ret, append(item, c)) + } + } + return ret + } + + return combination(candidates, target) +} + +``` \ No newline at end of file diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/invidam.go.md b/construct-binary-tree-from-preorder-and-inorder-traversal/invidam.go.md new file mode 100644 index 000000000..394b07c63 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/invidam.go.md @@ -0,0 +1,38 @@ +# Complexity +- Time complexity: $O(n)$ + - 원소의 크기 n에 대하여, 캐시 선언과 최악의 경우 순회에 비용 `n`이 발생한다. + +- Space complexity: $O(n)$ + - 원소의 크기 n에 대하여, 캐시 선언과 최악의 경우 순회(콜 스택)에 비용 `n`이 발생한다. +# Code +```go +func buildTree(preorder []int, inorder []int) *TreeNode { + cache := make(map[int]int) + + find := func(arr []int, val int) int { + if len(cache) == 0 { + cache = make(map[int]int, len(arr)) + for i, v := range arr { + cache[v] = i + } + } + return cache[val] + } + var organize func(preorder []int, inorder []int) *TreeNode + organize = func(preorder []int, inorder []int) *TreeNode { + if len(preorder) == 0 { + return nil + } + rootIdx := find(inorder, preorder[0]) - find(inorder, inorder[0]) + + return &TreeNode{ + Val: preorder[0], + Left: organize(preorder[1:rootIdx+1], inorder[:rootIdx]), + Right: organize(preorder[rootIdx+1:], inorder[rootIdx+1:]), + } + } + + return organize(preorder, inorder) +} + +``` \ No newline at end of file diff --git a/implement-trie-prefix-tree/invidam.go.md b/implement-trie-prefix-tree/invidam.go.md new file mode 100644 index 000000000..c781ddde5 --- /dev/null +++ b/implement-trie-prefix-tree/invidam.go.md @@ -0,0 +1,57 @@ +# Complexity +- Insert + - Time complexity: $$O(n)$$ + - `word`의 길이 n에 대하여, 깊이 n까지 재귀호출을 반복하는 비용이 발생한다. + - Space complexity: $$O(n)$$ + - `word`의 길이 n에 대하여, 깊이 n까지 트라이 구조를 만드는 비용이 발생한다. +- Search + - Time complexity: $$O(n)$$ + - `word`의 길이 n에 대하여, 깊이 n까지 재귀호출을 반복하는 비용이 발생한다. + - Space complexity: $$O(1)$$ + - 별도 비용이 발생하지 않는다. +# Code +```go +type Trie struct { + Val byte + IsTerminal bool + Nodes []*Trie +} + +func Constructor() Trie { + return Trie{Nodes: make([]*Trie, 26)} +} + +func (this *Trie) Insert(word string) { + if len(word) == 0 { + return + } + + if this.Nodes[word[0]-'a'] == nil { + newNode := Constructor() + this.Nodes[word[0]-'a'] = &newNode + this.Nodes[word[0]-'a'].Val = word[0] + } + this.Nodes[word[0]-'a'].Insert(word[1:]) +} + +func (this *Trie) Search(word string) bool { + if len(word) == 0 { + return this.IsTerminal + } + if this.Nodes[word[0]-'a'] == nil { + return false + } + return this.Nodes[word[0]-'a'].Search(word[1:]) +} + +func (this *Trie) StartsWith(prefix string) bool { + if len(prefix) == 0 { + return true + } + if this.Nodes[prefix[0]-'a'] == nil { + return false + } + return this.Nodes[prefix[0]-'a'].StartsWith(prefix[1:]) +} + +``` \ No newline at end of file diff --git a/kth-smallest-element-in-a-bst/invidam.go.md b/kth-smallest-element-in-a-bst/invidam.go.md new file mode 100644 index 000000000..be273182d --- /dev/null +++ b/kth-smallest-element-in-a-bst/invidam.go.md @@ -0,0 +1,28 @@ +# Complexity +- Time complexity: $$O(n)$$ + - 링크드 리스트의 길이 n에 대하여, 최악의 경우 모든 원소를 순회하므로 비용 `n`이 발생한다. + +- Space complexity: $$O(n)$$ + - 링크드 리스트의 길이 n에 대하여, 최악의 경우 모든 원소를 순회하며 콜 스택에서 비용 `n`이 발생한다. +# Code +```go +func sizeOf(root *TreeNode) int { + if root == nil { + return 0 + } + + return sizeOf(root.Left) + sizeOf(root.Right) + 1 +} + +func kthSmallest(root *TreeNode, k int) int { + leftSize := sizeOf(root.Left) + if k < leftSize+1 { + return kthSmallest(root.Left, k) + } else if k == leftSize+1 { + return root.Val + } else { + return kthSmallest(root.Right, k-leftSize-1) + } +} + +``` \ No newline at end of file diff --git a/word-search/invidam.go.md b/word-search/invidam.go.md new file mode 100644 index 000000000..229d1faa9 --- /dev/null +++ b/word-search/invidam.go.md @@ -0,0 +1,52 @@ +# Complexity +- Time complexity: $O(R*C)$ + - `board`의 행과 열이 크기인 R과 C에 대하여, 이들을 모두 순회할 수 있으므로 R*C가 소모된다. + +- Space complexity: $O(R*C)$ + - `board`의 행과 열이 크기인 R과 C에 대하여, 방문 여부를 기록하는 2차원 배열(`visited`)과 콜스택의 최대 크기 모두 R*C이다. +# Code +```go +var offsets = [][]int{ + {1, 0}, + {-1, 0}, + {0, 1}, + {0, -1}, +} + +func makeVisited(rows, cols int) [][]bool { + visited := make([][]bool, rows) + for i := range visited { + visited[i] = make([]bool, cols) + } + return visited +} + +func existFrom(board [][]byte, i int, j int, word string, visited [][]bool) bool { + if len(word) == 0 { + return true + } else if i < 0 || i >= len(board) || j < 0 || j >= len(board[0]) || board[i][j] != word[0] || visited[i][j] { + return false + } + visited[i][j] = true + defer func() { visited[i][j] = false }() + + for _, offset := range offsets { + if existFrom(board, i+offset[0], j+offset[1], word[1:], visited) { + return true + } + } + return false +} + +func exist(board [][]byte, word string) bool { + for i, row := range board { + for j, ch := range row { + if ch == word[0] && existFrom(board, i, j, word, makeVisited(len(board), len(board[0]))) { + return true + } + } + } + return false +} + +``` \ No newline at end of file