Skip to content
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] week2 #346

Merged
merged 10 commits into from
Aug 22, 2024
Merged

[Flynn] week2 #346

merged 10 commits into from
Aug 22, 2024

Conversation

obzva
Copy link
Contributor

@obzva obzva commented Aug 19, 2024

Problems

Description

Valid Anagram

각 알파벳이 몇 번 등장하는지 기록할 수 있도록 길이 26의 int 배열 count를 만듭니다.
문자열 s에 대한 반복문에서 각 알파벳의 등장 횟수를 기록합니다.
문자열 t에 대한 반복문에서는 각 알파벳이 등장할 때마다 count의 기록을 차감합니다.
마지막 반복문에서 count에 기록된 값이 0이 아닌 알파벳이 있다면 false를 반환하고, 별 일 없이 반복문을 탈출한다면 true를 반환합니다.

  • Time complexity: O(N)
    • 각 반복문이 순서대로 O(N), O(N), O(1)의 시간 복잡도를 가지므로 O(N)이라고 볼 수 있습니다.
  • Space complexity: O(1)
    • 배열의 크기가 26으로 정해져 있습니다.

Counting Bits

정답으로 반환해야하는 배열 res의 index i에 따라 아래와 같은 규칙을 가진다는 걸 확인할 수 있습니다.

if i == 0, then res[i] = 0
else for k such that 2^k <= i < 2^(k + 1), res[i] = res[i - 2^k]

이해를 돕기 위해 아래 표를 보면, 정수 4 ~ 7 의 이진 표현은 0 ~ 3 의 이진 표현 왼쪽에 1이 추가된 것이라는 사실을 알 수 있습니다.

num bin res
0 0000 0
1 0001 1
2 0010 1
3 0011 2
4 0100 1
5 0101 2
6 0110 2
7 0111 3
  • Time complexity: O(N)
    • 첫번째 반복문이 O(N)의 시간 복잡도를 가집니다.
  • Space complexity: O(1)
    • 반환하는 배열 외에 별도의 공간이 소모되지 않습니다.

Encode and Decode Strings

Chunked transfer encoding를 이용했습니다.
각 문자열마다 아래와 같은 방식으로 인코딩/디코딩했습니다.

string <---encode/decode---> size of string + '.' + string

주어진 모든 문자열의 길이의 합을 N, 가장 길이가 긴 문자열의 길이를 M이라고 했을 때 Big-O 분석은 다음과 같습니다.

  • encode
    • Time compleixty: O(N)
    • Space complexity: O(1)
  • decode
    • Time complexity: O(NM)
    • Space complexity: O(M)
      • 현재 decoding 중인 문자열을 저장하는 tmp의 크기가 최대 M입니다

Construct Binary Tree from Preorder and Inorder Traversal

stack을 이용한 iterative solution입니다.
inorder traversepreorder traverse의 성질을 이용하면, stack의 top현재 nodeparent인지 아닌지를 판단할 수 있습니다.
parent의 leftinorder 배열에서 parent보다 왼편에 있는 요소 중 가장 오른편에 있는 요소여야 합니다.
stack의 topinorder 배열에서 현재 node보다 더 오른편에 있다면, stack의 top이 현재 node보다 오른편에 있는 요소 중 가장 왼편에 있는 요소임이 분명하기 때문에 stack의 top은 현재 node의 부모라고 판단할 수 있습니다.
왜냐하면 아래 코드에서 우리는 각 요소를 preorder 배열의 순서대로 조회하고 있기 때문입니다.
비슷하게, parent의 rightinorder 배열에서 parent보다 오른편에 있는 요소 중 가장 왼편에 있는 요소여야 합니다.
현재 stack의 topstack에 쌓여있는 요소들 중 inorder 배열 상 가장 왼편에 있는 요소입니다.
따라서 parent에 조건에 부합한 요소가 나올 때 까지 pop을 반복해주면 현재 node의 부모를 찾을 수 있습니다.

  • Time complexity: O(N)
    • inorder 배열의 각 요소에 index를 mapping하기 위해 inorder_index_map을 만들었고 이건 O(N)의 시간 복잡도를 가집니다.
    • preorder배열의 순서대로 요소를 조회하며 Tree를 생성합니다. push혹은 pop연산이 실행되는 경우가 있지만, 각 연산은 요소당 최대 1회씩만 실행되기 때문에 이 반복문 또한 O(N)의 시간 복잡도를 가집니다.
  • Space complexity: O(N)
    • inorder_index_map이 O(N)의 공간 복잡도를 가집니다
    • tree_stack 또한 O(N)의 공간 복잡도를 가집니다. Tree가 왼편으로 심하게 치우쳐 있을 경우도 존재하기 때문입니다.

Decode Ways

BFS 방식으로 풀이할 경우, 11111...11111111과 같은 test case에 대해 O(2^N)의 시간복잡도를 가지므로 제한 시간 안에 문제를 풀 수 없습니다.
memo라는 배열을 정의합니다.

if i == 0, then memo[i] = 1
else, memo[i] = 's.substr(0, i)를 decode할 수 있는 방법의 수'

만약 s[i - 1]0이 아니라면, s.substr(0, i - 1)를 decode할 방법들을 그대로 사용할 수 있으므로 memo[i]memo[i - 1]입니다.
또한 만약 s.substr(i - 2, 2)이 10 이상 26이하의 정수라면 s.substr(0, i - 2)를 decode하는 방법을 추가할 수 있으므로 memo[i] += memo[i - 2]입니다.

  • Time complexity: O(N)
  • Space complexity: O(N)

@obzva obzva requested a review from kim-young August 20, 2024 07:32
Copy link
Contributor

@DaleSeo DaleSeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

무시하셔도 되는 아주 사소한 피드백 드립니다 🙂

encode-and-decode-strings/flynn.cpp Show resolved Hide resolved
encode-and-decode-strings/flynn.cpp Outdated Show resolved Hide resolved
encode-and-decode-strings/flynn.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@DaleSeo DaleSeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Comment on lines +28 to +45
TreeNode* root = new TreeNode(preorder[0]);
tree_stack.push(root);

for (int i = 1; i < preorder.size(); i++) {
TreeNode* curr = new TreeNode(preorder[i]);

if (inorder_index_map[curr->val] < inorder_index_map[tree_stack.top()->val]) {
tree_stack.top()->left = curr;
} else {
TreeNode* parent;
while (!tree_stack.empty() && inorder_index_map[curr->val] > inorder_index_map[tree_stack.top()->val]) {
parent = tree_stack.top();
tree_stack.pop();
}
parent->right = curr;
}
tree_stack.push(curr);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 풀이 너무 아름답습니다! 😍
혹시 다음 모임 때 다른 멤버들한테 설명 좀 해주실 수 있으실까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 ㅎㅎ 준비해보겠습니다
(+ line 여러개에 대해 코멘트를 남길 수도 있군요.. 배워갑니다!)

@obzva obzva merged commit 4c472a7 into DaleStudy:main Aug 22, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Status: Completed
Development

Successfully merging this pull request may close these issues.

3 participants