-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Flynn] Week 15 #608
Merged
Merged
[Flynn] Week 15 #608
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4ef6503
add solution: subtree of another tree
obzva f386b93
add solution: validate binary search tree
obzva 575b17e
add solution: longest palindromic substring
obzva 8112a9c
add solution: rotate image
obzva cf06fdb
add solution: alien dictionary
obzva File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,105 @@ | ||
/* | ||
풀이 | ||
- 두 단어를 알파벳 하나씩 차례대로 비교했을 때, 첫번째 차이가 발생하는 지점에서 alien dictionary의 order를 찾을 수 있습니다 | ||
- 첫번째 단어부터 바로 그 다음 단어와 두 단어씩 짝지어서 비교하면 앞에서 말한 일련의 order를 찾아낼 수 있습니다 | ||
알파벳 x가 알파벳 y보다 alien dictionary order에서 앞서는 관계, 즉 x->y인 관계를 찾아서 x: {y1, y2, y3, ...}인 집합의 map을 만들겠습니다 | ||
그리고 이를 nextLetters라고 명명하였습니다 | ||
- 만약 특정 알파벳 x에 대해, z->x인 알파벳 z가 없다면 x는 우리가 정답으로 제출할 result string의 어느 위치에든 자유롭게 끼워넣을 수 있습니다 | ||
(* If there are multiple solutions, return any of them.) | ||
우리는 이런 알파벳 x를 찾아낼 때마다 바로바로 result string res에 추가하겠습니다 | ||
- z->x인 알파벳 z가 현재 있는지 없는지에 대한 상태관리를 하기 위해서 prevLetterCounts라는 map을 만들겠습니다 | ||
prevLetterCounts[x]: z->x인 z의 개수 | ||
- nextLetters, prevLetterCounts를 잘 생성한 후에는 prevLetterCount가 0인 알파벳부터 queue에 등록시킨 후 BFS를 실행합니다 | ||
BFS를 실행하며 prevLetterCount가 0인 알파벳이 새로 발견될 경우 queue에 등록시킵니다 | ||
- 엣지케이스가 두 경우 발생하는데, | ||
첫번째는 nextLetters를 생성하는 반복문에서 발견됩니다 | ||
두번째 단어가 첫번째 단어의 prefix인 경우는 애초부터 잘못된 dictionary order인 경우입니다 | ||
위 경우는 단순 알파벳 비교로는 발견하기 어려우므로 flag를 사용하였습니다 | ||
두번째는 result string의 길이가 input으로 주어진 단어들에 등장한 알파벳의 개수보다 적은 경우입니다 | ||
이 경우는 nextLetters에 순환이 발생한 경우이므로 dictionary order가 잘못되었다고 판단할 수 있습니다 | ||
Big O | ||
- N: 주어진 배열 words의 길이 | ||
- S(W): 배열 words에 속한 모든 string의 길이의 총합 | ||
- Time complexity: O(N + S(W)) | ||
- prevLetterCounts와 nextLetters 생성 -> O(N) | ||
- nextLetters에 들어갈 알파벳 전후관계 찾기 -> O(S(W)) | ||
- 알파벳 소문자의 수는 제한되어 있기 때문에 BFS의 시간 복잡도 상한선은 정해져 있습니다 -> O(26 * 26) = O(1) | ||
- Space complexity: O(1) | ||
- 알파벳 소문자의 수는 제한되어 있기 때문에 공간 복잡도의 상한선은 정해져 있습니다 | ||
prevLetterCounts -> O(26) = O(1) | ||
nextLetters -> O(26 * 26) = O(1) | ||
queue -> O(26) = O(1) | ||
*/ | ||
|
||
import "strings" | ||
|
||
func alienOrder(words []string) string { | ||
n := len(words) | ||
// prevLetterCounts[x] = count of letters y that are in relation of y->x | ||
prevLetterCounts := make(map[string]int) | ||
// nextLetters[x] = set of letters y that are in relation of x->y | ||
nextLetters := make(map[string]map[string]bool) | ||
for _, word := range words { | ||
for _, c := range word { | ||
if _, ok := prevLetterCounts[string(c)]; !ok { | ||
prevLetterCounts[string(c)] = 0 | ||
nextLetters[string(c)] = make(map[string]bool) | ||
} | ||
} | ||
} | ||
|
||
for i := 0; i < n-1; i++ { | ||
currWord := words[i] | ||
nextWord := words[i+1] | ||
// flag for edge case below | ||
diff := false | ||
for j := 0; j < len(currWord) && j < len(nextWord); j++ { | ||
if currWord[j] != nextWord[j] { | ||
diff = true | ||
if _, ok := nextLetters[string(currWord[j])][string(nextWord[j])]; !ok { | ||
prevLetterCounts[string(nextWord[j])]++ | ||
nextLetters[string(currWord[j])][string(nextWord[j])] = true | ||
} | ||
break | ||
} | ||
} | ||
// tricky edge case!!! | ||
// if nextWord is prefix of currWord, then the provided dictionary order is invalid | ||
if !diff && len(currWord) > len(nextWord) { | ||
return "" | ||
} | ||
} | ||
// BFS | ||
queue := make([]string, 0, len(prevLetterCounts)) | ||
for letter := range prevLetterCounts { | ||
// we can arrange letters whose prevLetterCount is zero as we wish | ||
if prevLetterCounts[letter] == 0 { | ||
queue = append(queue, letter) | ||
} | ||
} | ||
// in Go, using strings.Builder is the most efficient way to build strings | ||
var sb strings.Builder | ||
for len(queue) > 0 { | ||
// pop the letter from the queue and append it to the result string | ||
popped := queue[0] | ||
queue = queue[1:] | ||
sb.WriteString(popped) | ||
|
||
for nextLetter := range nextLetters[popped] { | ||
prevLetterCounts[nextLetter]-- | ||
// if prevLetterCount for nextLetter becomes zero, we can add it to the queue | ||
// append to the result string (order) in the next iteration | ||
if prevLetterCounts[nextLetter] == 0 { | ||
queue = append(queue, nextLetter) | ||
} | ||
} | ||
} | ||
// res is result string | ||
res := sb.String() | ||
// this case means that there was a cycle | ||
if len(res) != len(prevLetterCounts) { | ||
return "" | ||
} | ||
// else return res | ||
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,54 @@ | ||
/* | ||
풀이 | ||
- 슬라이딩 윈도우 기법을 이용하면 풀이할 수 있습니다 | ||
Big O | ||
- N: 주어진 문자열 s의 길이 | ||
- Time complexity: O(N^2) | ||
- window 함수가 O(N)의 시간복잡도를 가지므로 | ||
각 반복문은 O(N * N) = O(N^2)의 시간복잡도를 가진다고 볼 수 있습니다 | ||
- Space complexity: O(1) | ||
- 별도의 추가적인 공간 복잡도를 고려하지 않아도 됩니다 | ||
*/ | ||
|
||
func longestPalindrome(s string) string { | ||
n := len(s) | ||
maxStart := 0 | ||
maxEnd := 0 | ||
// for odd lengths | ||
for i := 0; i < n; i++ { | ||
window(&s, &maxStart, &maxEnd, i, false) | ||
} | ||
// for even lengths | ||
for i := 0; i < n-1; i++ { | ||
window(&s, &maxStart, &maxEnd, i, true) | ||
} | ||
|
||
return s[maxStart : maxEnd+1] | ||
} | ||
|
||
/* | ||
helper function for searching palindromic substring | ||
from the pivotal index `i` | ||
*/ | ||
func window(s *string, maxStart *int, maxEnd *int, i int, isEven bool) { | ||
n := len(*s) | ||
start := i | ||
end := i | ||
if isEven { | ||
end++ | ||
} | ||
for 0 <= start && end < n { | ||
if (*s)[start] != (*s)[end] { | ||
break | ||
} | ||
|
||
// if new palindromic substring is longer than the previously found one, | ||
// update the start and end index | ||
if *maxEnd-*maxStart < end-start { | ||
*maxStart = start | ||
*maxEnd = end | ||
} | ||
start-- | ||
end++ | ||
} | ||
} |
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,39 @@ | ||
/* | ||
풀이 | ||
- matrix를 4사분면으로 나눕니다 | ||
1사분면의 모든 좌표에 대해 아래와 같은 연산을 수행합니다 | ||
- 1사분면의 좌표 a1에 대해 a2, a3, a4를 아래처럼 정의합니다 | ||
a2: a1을 90도 회전시켰을 때의 좌표 (2사분면에 위치함) | ||
a3: a2를 90도 회전시켰을 때의 좌표 (3사분면에 위치함) | ||
a4: a3을 90도 회전시켰을 때의 좌표 (4사분면에 위치함) | ||
a1 -> a2, a2 -> a3, a3 -> a4, a4 -> a1으로 값을 변경시킵니다 | ||
Big O | ||
- N: 매트릭스의 크기 | ||
- Time complexity: O(N^2) | ||
- Space complexity: O(1) | ||
*/ | ||
|
||
func rotate(matrix [][]int) { | ||
n := len(matrix) | ||
// 사분면의 크기, qr, qc: 사분면의 행, 열 크기 | ||
qr := n / 2 | ||
qc := (n + 1) / 2 | ||
|
||
for r := 0; r < qr; r++ { | ||
for c := 0; c < qc; c++ { | ||
r1 := r | ||
c1 := c | ||
|
||
r2 := c | ||
c2 := n - 1 - r | ||
|
||
r3 := n - 1 - r | ||
c3 := n - 1 - c | ||
|
||
r4 := n - 1 - c | ||
c4 := r | ||
|
||
matrix[r1][c1], matrix[r2][c2], matrix[r3][c3], matrix[r4][c4] = matrix[r4][c4], matrix[r1][c1], matrix[r2][c2], matrix[r3][c3] | ||
} | ||
} | ||
} | ||
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,50 @@ | ||
/* | ||
풀이 | ||
- 두 트리가 동일한지 검사하는 dfs 함수를 이용하여 풀이할 수 있습니다 | ||
Big O | ||
- M: root 트리의 노드 개수 | ||
- N: subRoot 트리의 노드 개수 | ||
- Time complexity: O(MN) | ||
- 최악의 경우 root 트리의 모든 노드에 대해 isSameTree 함수를 실행 (O(M)) | ||
최악의 경우 isSameTree 함수는 O(N)의 시간복잡도를 가짐 | ||
- Space complexity: O(M+N) | ||
- isSubTree의 재귀호출스택 깊이는 최대 O(M)의 공간복잡도를 가짐 | ||
- isSameTree의 재귀호출스택 깊이는 최대 O(N)의 공간복잡도를 가짐 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
func isSubtree(root *TreeNode, subRoot *TreeNode) bool { | ||
// handling nil(null) inputs | ||
if root == nil { | ||
return false | ||
} | ||
// return true if root and subroot are same | ||
if isSameTree(root, subRoot) { | ||
return true | ||
} | ||
// else, check root.left and root.right | ||
return isSubtree(root.Left, subRoot) || isSubtree(root.Right, subRoot) | ||
} | ||
|
||
/* | ||
dfs helper function checking whether two treenodes are same or not | ||
*/ | ||
func isSameTree(a *TreeNode, b *TreeNode) bool { | ||
// handling nil(null) cases | ||
if a == nil || b == nil { | ||
return a == b | ||
} | ||
// falsy cases | ||
if a.Val != b.Val || !isSameTree(a.Left, b.Left) || !isSameTree(a.Right, b.Right) { | ||
return false | ||
} | ||
// else, return true | ||
return true | ||
} |
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,46 @@ | ||
/* | ||
풀이 | ||
- BST의 속성을 이해한 후, 해당 속성을 검사하는 dfs 함수를 이용하면 풀이할 수 있습니다 | ||
Big O | ||
- N: root 트리의 노드 개수 | ||
- Time complexity: O(N) | ||
- 모든 노드에 대해 최대 1번의 탐색이 필요합니다 | ||
- Space complexity: O(logN) (O(N) at worst) | ||
- check 함수의 재귀호출 스택 깊이는 트리의 높이에 비례하여 증가하므로 일반적으로 O(logN)의 공간복잡도를 가진다고 볼 수 있습니다 | ||
하지만 트리가 심하게 치우친 경우 O(N)까지 커질 수 있습니다 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
|
||
const ( | ||
MIN = -(2_147_483_648 + 1) | ||
MAX = 2_147_483_647 + 1 | ||
) | ||
|
||
func isValidBST(root *TreeNode) bool { | ||
return check(root.Left, MIN, root.Val) && check(root.Right, root.Val, MAX) | ||
} | ||
|
||
/* | ||
helper dfs function | ||
*/ | ||
|
||
func check(node *TreeNode, min int, max int) bool { | ||
// base case | ||
if node == nil { | ||
return true | ||
} | ||
// node.val should be in the boundary (min, max) | ||
if !(min < node.Val && node.Val < max) { | ||
return false | ||
} | ||
// check for children nodes | ||
return check(node.Left, min, node.Val) && check(node.Right, node.Val, max) | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도움이 되실까 싶어 남기자면, 선형대수학에서 transpose + reverse row로도 구현도 가능합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 @lymchgmk 님 풀이 정말 맛있게 잘 봤습니다 ㅎㅎㅎ