Skip to content

[uraflower] Week 15 Solutions #1663

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

Merged
merged 6 commits into from
Jul 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions alien-dictionary/uraflower.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* @param words: a list of words
* @return: a string which is correct order
*/
const alienOrder = (words) => {
const graph = {};

// 초기화
for (const word of words) {
for (const char of word) {
if (!graph[char]) {
graph[char] = new Set();
}
}
}

// 그래프 생성
for (let i = 1; i < words.length; i++) {
const prev = words[i - 1];
const current = words[i];
let found = false;

const minLen = Math.min(prev.length, current.length);
for (let j = 0; j < minLen; j++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

minLen 내 인덱스 범위에서 prevcurrent 간 문자쌍 중 처음으로 서로 다른 문자까지만 graph에 추가해야 할 것 같은데요(그 이후 문자는 더이상 비교할 수 없기 때문), 현재 코드에서는 minLen까지 모든 범위에 대해 graph를 구성하고 있는 것 같아요!

그리고 현재 코드에서는 found 변수를 true로 바꾸는 코드가 없어서 항상 false 인 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헉 제가 무료 버전에서 풀다가 실행시키려고 다른 편집기에서 작성했는데 그래서 풀다 만 버전으로 잘못 올렸네요.
꼼꼼히 봐주시고 말씀해주셔서 정말 감사합니다! 😄

if (prev[j] !== current[j]) {
graph[prev[j]].add(current[j]);
found = true;
break;
}
}
// 모순 처리
if (!found && prev.length > current.length) {
return '';
}
}

// 탐색
const output = [];
const visiting = new Set();
const visited = new Set();

function dfs(current) {
if (visiting.has(current)) {
return false;
}
if (visited.has(current)) {
return true;
}

visiting.add(current);
for (const adj of graph[current]) {
if (!dfs(adj)) {
return false;
}
}
visiting.delete(current);

visited.add(current);
Copy link
Contributor

Choose a reason for hiding this comment

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

저는 이 문제를 위상정렬(BFS)로 풀었는데요, DFS로 풀려면 indegree를 기록할 필요 없이 이렇게 상태를 하나 더 유지해서 풀 수 있군요! visitingvisited라는 네이밍이 직관적이어서 이해하기 쉬웠습니다 🤩

output.push(current);
return true;
}

// 순회
for (const node in graph) {
if (!dfs(node)) {
return '';
}
}

return output.reverse().join('');
}


// 방향 그래프로 선행되는 순서를 표현
// 비슷한 문제: https://leetcode.com/problems/course-schedule/description/

// 위상정렬 사용해서 진입차수 기준 정렬하는 방법도 있음
// 너무 어려웠다...
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 접근법
// preorder: v l r
// inorder: l v r

// preorder의 가장 첫 요소는 무조건 root
// inorder에서 root보다 왼쪽에 있는 요소는 전부 left임
// 여기서 중복되는 value가 없어야 하는데 문제에서 없음을 보장함
// 따라서 preorder[0]을 inorder에서 찾고
// 그 왼쪽, 오른쪽으로 배열을 나눠서 이걸 반복

/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
const buildTree = function (preorder, inorder) {
let preorderIndex = 0;
const map = inorder.reduce((map, val, index) => {
map[val] = index;
return map;
}, {});

function build(start, end) {
if (start > end) {
return null;
}

const root = new TreeNode(preorder[preorderIndex++]);
const index = map[root.val];

root.left = build(start, index - 1);
root.right = build(index + 1, end);

return root;
}

return build(0, inorder.length - 1);
};

// 시간복잡도: O(n)
// 공간복잡도: O(n)
30 changes: 30 additions & 0 deletions longest-palindromic-substring/uraflower.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @param {string} s
* @return {string}
*/
const longestPalindrome = function(s) {
let substr = '';

for (let i = 0; i < s.length; i++) {
const oddStr = getCurrentLongestPalindrome(i, i); // s[i] 기준 양옆으로 뻗어나감 => length는 항상 홀수
const evenStr = getCurrentLongestPalindrome(i, i+1); // s[i] + s[i+1] 기준 양옆으로 => length는 항상 짝수

if (substr.length < oddStr.length) substr = oddStr;
if (substr.length < evenStr.length) substr = evenStr;
}

// 기준 문자열을 포함하면서 가장 긴 팰린드롬을 찾아 반환하는 함수 (기준 문자열: s.slice(l, r + 1))
const getCurrentLongestPalindrome = function (l, r) {
while (0 <= l && r < s.length && s[l] === s[r]) {
l--;
r++;
}

return s.slice(l+1, r);
}

return substr;
};

// 시간복잡도: O(n^2)
// 공간복잡도: O(s) (s: substr.length)
52 changes: 52 additions & 0 deletions rotate-image/uraflower.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @param {number[][]} matrix
* @return {void} Do not return anything, modify matrix in-place instead.
*/
const rotate = function (matrix) {
const n = matrix.length;

// 상하좌우 겉에서부터 한 겹씩 안으로 진입
for (let layer = 0; layer < Math.floor(n / 2); layer++) {

// layer 위의 각 칸들을 rotate
// 하나를 rotate했을 때 연쇄적으로 rotate되는 규칙을 이용해
// 네 칸 rotate하는 걸 x번 반복함

// x = n - 2 * layer - 1
// 전체 배열 크기 n에서 layer만큼 안쪽으로 들어가야 하는데
// 상하, 좌우만큼 들어가야 하니까 2를 곱함
// 1을 안 빼면 이미 rotate한 자리를 다시 rotate하므로 빼줌

for (let i = 0; i < n - 2 * layer - 1; i++) {
const top = layer;
const bottom = n - 1 - layer;
const left = top;
const right = bottom;

const topLeft = matrix[top][left + i];
matrix[top][left + i] = matrix[bottom - i][left];
matrix[bottom - i][left] = matrix[bottom][right - i];
matrix[bottom][right - i] = matrix[top + i][right];
matrix[top + i][right] = topLeft;
}
}
};

// 시간복잡도: O(n^2)
// 공간복잡도: O(1)

// 참고로 중첩 구조를 다음과 같이 바꿔도 됨
const top = 0;
const bottom = n - 1;

while (top < bototm) {
const left = top;
const right = bottom;

for (let i = top; i < bottom; i ++) {
// rotate
}

top++;
bottom--;
}
49 changes: 49 additions & 0 deletions subtree-of-another-tree/uraflower.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} subRoot
* @return {boolean}
*/
const isSubtree = function(root, subRoot) {
const isSame = function(node1, node2) {
if (!node1 && !node2) return true;
if (node1?.val !== node2?.val) return false;

return isSame(node1.left, node2.left) && isSame(node1.right, node2.right);
}

const queue = [root];

while (queue.length) {
const node = queue.shift();

if (node.left) {
queue.push(node.left);
}

if (node.right) {
queue.push(node.right);
}

if (isSame(node, subRoot)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

BFS로 root 트리를 순회하는 동작과 재귀적으로 subRoot 트리와 비교하는 동작을 정말 깔끔하게 구현하신 것 같아요!

return true;
}
}

return false;
};

// 다른 접근법:
// 정렬해서 비교하는 방식 => left, right 구분이 안가는 문제
// 정렬할 때 left, right 정보를 포함해서 직렬화하면 됨
// 이렇게 하면 복잡도 면에서 성능이 더 좋음

// 시간복잡도: O(n * m) (n: root size, m: subroot size)
// 공간복잡도: O(n + m)