Skip to content

[jdy8739] week 8 #955

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 9 commits into from
Jan 31, 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
82 changes: 82 additions & 0 deletions clone-graph/jdy8739.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* // Definition for a _Node.
* function _Node(val, neighbors) {
* this.val = val === undefined ? 0 : val;
* this.neighbors = neighbors === undefined ? [] : neighbors;
* };
*/

/**
* @param {_Node} node
* @return {_Node}
*/
var cloneGraph = function (node) {
const nodeMap = new Map();

const dfs = (nodeParam) => {
if (!nodeParam) {
return null;
}

if (nodeMap.has(nodeParam.val)) {
return nodeMap.get(nodeParam.val);
}

const clone = new Node(nodeParam.val);

nodeMap.set(clone.val, clone);

for (const nei of nodeParam.neighbors) {
clone.neighbors = [...clone.neighbors, dfs(nei)];
Copy link
Contributor

Choose a reason for hiding this comment

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

Array를 매번 새로 만들어주는 대신에 새 원소를 push해주는 방식은 어떤가요?

Suggested change
clone.neighbors = [...clone.neighbors, dfs(nei)];
clone.neighbors.push(dfs(nei));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 풀이에 그렇게 push로 원소를 넣어 주던데 그 방식이 좀 더 간결하고 성능도 나은 것 같습니다 :)

}

return clone;
}

return dfs(node);
};

// 재귀를 활용한 dfs를 사용한 풀이
// 시간복잡도 O(n + e) -> n(노드의 수) + e(간선의 수) 만큼 탐색을 수행
// 공간복잡도 O(n) -> map이 총 노드의 수 만큼 크기를 가짐
Copy link
Contributor

Choose a reason for hiding this comment

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

  • 공간복잡도 분서 결과에는 영향을 미치지 않지만, 재귀호출 스택에 대한 언급도 해주면 좋을 것 같아요!
  • 시간복잡도에서 노드의 수를 v라고 표현하셨으니까 공간복잡도도 O(v)라고 써주면 더 나을 것 같아요


// ------------------------------------

/**
* @param {_Node} node
* @return {_Node}
*/
var cloneGraph = function(node) {
if (!node) {
return null;
}

const clone = new Node(node.val);

const clonedNodeMap = new Map().set(clone.val, clone);

// 이 queue에는 클론이 아니라 원본 노드가 들어가야함(neighbors에 대한 참조 때문)
const queue = [node];
Comment on lines +58 to +59
Copy link
Contributor

Choose a reason for hiding this comment

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

알고리즘은 정상적으로 동작하지만 해당 Array는 queue가 아니네요 (stack처럼 동작해요!)


while (queue.length > 0) {
const currentNode = queue.pop();

const currentNodeClone = clonedNodeMap.get(currentNode.val);

for (const nei of currentNode.neighbors) {
if (!clonedNodeMap.has(nei.val)) {
clonedNodeMap.set(nei.val, new Node(nei.val));
queue.push(nei);
}

currentNodeClone.neighbors = [...currentNodeClone.neighbors, clonedNodeMap.get(nei.val)];
}
}

return clone;
};

// 큐를 활용한 bfs를 사용한 풀이
// 시간복잡도 O(n + e) -> n(노드의 수) + e(간선의 수) 만큼 탐색을 수행
// 공간복잡도 O(n) -> map이 총 노드의 수 만큼 크기를 가짐
Copy link
Contributor

Choose a reason for hiding this comment

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

시간복잡도에서 노드의 수를 v라고 표현하셨으니까 공간복잡도도 O(v)라고 써주면 더 나을 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그러네요 수정해서 커밋하겠습니다. 감사합니다! :)


35 changes: 35 additions & 0 deletions longest-common-subsequence/jdy8739.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @param {string} text1
* @param {string} text2
* @return {number}
*/
var longestCommonSubsequence = function(text1, text2) {
const resultMap = new Map();

const dfs = (i, j) => {
const mapKey = `${i}-${j}`;

if (resultMap.has(mapKey)) {
return resultMap.get(mapKey);
}

if (i === text1.length || j === text2.length) {
return 0;
}

if (text1[i] === text2[j]) {
const resultHit = 1 + dfs(i + 1, j + 1);
resultMap.set(mapKey, resultHit);
return resultHit;
}

const resultMiss = Math.max(dfs(i + 1, j), dfs(i, j + 1));
resultMap.set(mapKey, resultMiss);
return resultMiss;
}

return dfs(0, 0);
};

// 시간복잡도 O(m * n) -> 재귀를 통해 m과 n이 1씩 증가하면서 상대편의 m or n 번 째 인덱스 문자열을 비교하므로??? (잘 모르겠습니다. 리뷰어분이 여유되시면 설명부탁드립니다 ㅜㅜ)
Copy link
Contributor

Choose a reason for hiding this comment

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

어디까지 이해되셨고 어디부터 이해가 잘 안되시는지 Discussion에 올려주세요~!

// 공간복잡도 O(m * n) -> 맵에 키가 m * n개로 최대로 요소가 들어옴
51 changes: 51 additions & 0 deletions longest-repeating-character-replacement/jdy8739.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @param {string} s
* @param {number} k
* @return {number}
*/
var characterReplacement = function(s, k) {
let start = 0;
let end = 0;
let maxLength = 0;
let maxCountOfChar = 0;

const charMap = new Map();
charMap.set(s[end], 1);

while (end < s.length) {
maxCountOfChar = Math.max(maxCountOfChar, charMap.get(s[end]));

const currLength = end - start + 1;

const countOfOthers = currLength - maxCountOfChar;

// 현재 문자열의 길이에서 가장 많이 나오는 문자열의 수를 뺸 값인 countOfOthers가
// k보다 작으면 현재 문자열에서 start번 째 문자의 수를 map에서 감소시키고 star의 값을 증가시킨다.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo) k보다 크면

if (countOfOthers > k) {
const startCharCount = charMap.get(s[start]);
charMap.set(s[start], startCharCount - 1);

start++;
} else {
// countOfOthers가 k보다 같거나 작을 경우 k번 문자를 바꾸는 것으로 현재 문자열을 모두 하나의 문자로 통일시킬 수 있다는 것으로
// 현재 문자열에서 end번 째 문자의 수를 map에서 증가시킨다.
// 이후 end의 값을 증가시킨다.
end++;

const endCharCount = charMap.get(s[end]);

if (endCharCount) {
charMap.set(s[end], endCharCount + 1);
} else {
charMap.set(s[end], 1);
}
}

maxLength = Math.max(maxLength, Math.min(maxCountOfChar + k, currLength));
}

return maxLength;
};

// 시간복잡도 O(n) -> 슬라이딩 윈도우기법으로 최대 1번 순회한다.
// 공간복잡도 O(1) -> map의 크기는 알파벳의 갯수인 최대 26개이다.
34 changes: 34 additions & 0 deletions number-of-1-bits/jdy8739.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @param {number} n
* @return {number}
*/
var hammingWeight = function (n) {
const binary = [1];

while (binary[0] < n) {
const latest = binary[0] * 2;

binary.unshift(latest);
}

let count = 0;

for (let i = 0; i < binary.length; i++) {
if (binary[i] <= n) {
count++;
n = n - binary[i];
}

if (n === 0) {
break;
}
}

return count;
};

// 시간복잡도 O(logn) -> 이진탐색처럼 2씩 곱해가며 n을 넘어가는 가장 큰 수를 찾으므로
Comment on lines +1 to +30
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. bitwise연산자에 대해서 한 번 찾아보시는 걸 추천드립니다 e.g. Right shift. bitwise 연산자를 이용한 풀이가 떠오르지 않는다면 다른 분들 풀이를 참고해주세요~!
  2. 제가 알기론 unshift의 시간 복잡도는 O(1)이 아닙니다. (이 부분도 찾아보시는게 좋을 것 같아요) 따라서 해당 풀이의 시간 복잡도 분석도 다시 이뤄져야할 것 같다는 생각이 듭니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

js의 배열이 원소들이 연달아 주소값을 가지는 형태가 아니다보니 O(1)라고 생각했는데요, 한 번 알아보고 주석을 다시 달아 커밋하겠습니다. 코멘트 감사합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

js의 unshift는 배열의 요소가 맨 앞에 추가될 때마다 뒤 모든 요소들의 index가 1 씩 추가되므로 O(n)의 복잡도를 갖는다는 것을 알게되었습니다!!

  1. JavaScript 배열의 내부 구조
    JavaScript 엔진(V8 기준)에서 배열은 두 가지 형태로 저장될 수 있습니다.

✅ (1) Packed Elements (연속된 메모리, 빠름)
배열이 숫자로만 이루어져 있고, 인덱스가 연속적이면
내부적으로 일반적인 동적 배열처럼 연속된 메모리에 저장됨
O(1)로 빠른 조회가 가능

let arr = [1, 2, 3, 4]; // Packed Elements 사용
✅ (2) Sparse Elements (비연속적, 느림)
배열이 중간에 빈 요소가 있거나, 숫자가 아닌 객체가 포함된 경우
내부적으로 해시 테이블(Hash Map)처럼 동작
요소를 조회할 때 해시 테이블에서 검색해야 하므로 느려짐 (O(1) → O(n))

let arr = [];
arr[0] = 1;
arr[100] = 2; // 희소 배열 (Sparse Array)
✅ 위처럼 인덱스가 연속되지 않으면 메모리가 연속적이지 않음!


// 수정된 시간복잡도 -> 위의 while 문에서 O(logn)의 시간복잡도를 수행하면서 O(n)의 시간복잡도를 갖는 unshift 메소드를 사용하며
// for문에서 다시 O(logn)의 시간복잡도의 루프를 돌기 때문에
// 총 복잡도는 O(logn) * binary 배열의 길이 + O(logn)