Skip to content

[grapefruitgreentealoe] WEEK 02 Solutions #1730

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
102 changes: 102 additions & 0 deletions 3sum/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//1.dfs로 풀기 : 시간초과 남


/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
/*
arr: 현재 고정 배열을 뜻함. dfs가 돌때마다 변경됨.
start: 끝난 index. arr와 마찬가지로 이것은 for문안에서 변경될 예정.
dep: dep은 현재 dfs의 dep+1을 해주면 됨.
*/
const numsLength = nums.length
if(numsLength ==3 && nums.reduce((a,b)=>a+b,0) == 0) return [nums]

const ret = []
const seen = new Set();
nums.sort((a, b) => a - b);

function dfs(arr,start,dep){
if(dep == 3) {
if(arr.length !==3) return
const arrTotal = arr.reduce((a,b)=>a+b,0);
if(arrTotal == 0){
const string = [...arr].sort((a,b)=>a-b).join(',')
if(!seen.has(string)){
seen.add(string)
ret.push(arr)
}
}
return
}
//만약 start가 0이 되면, i를 감소시켜야하고, 새로운 배열을 추가해야한다. 기존의 배열에 넣어주는게 아니다.

//끝점을 증가시키면서 진행해야함. 현재 고정 arr에 끝점 그 앞의 idx부터 진행해서 0까지 감소시키면서 dfs를 돌리면 된다.
//idx가 i-1부터이므로, i는 최소 1이어야 가능하다.
for(let idx = start; idx<numsLength; idx++){
// currArr.push([...arr,nums[idx]])
//현재 i에 대한 현재 currArr를 만들어준다.
//만들어준 각 Arr에 대해서, 다시 dfs로 들어가서, 각 배열의 내부의 합이 0인지 확인하고,
//현재 배열에 대한 set에 대해서 중복이 되는 것은 없는지 확인하면서 넣어준다.
dfs([...arr,nums[idx]],idx+1,dep+1)
}}
dfs([],0,0)
//마지막에 set으로 triples의 중복을 제거해줘야한다.

return ret
};

/*
시간복잡도:
nums.sort((a, b) => a - b): 배열 정렬에 O(NlogN)

N개 숫자 중 3개 선택하는 조합 수 N(N−1)(N−2)/6
정확히 알 수는 없지만,

N^3 이상으로 보임.

공간복잡도 : O(N^3) => seen 때문.

*/

//2. 투포인터로 풀기

/*
우선 내가 문제에 대한 이해가 틀렸다. 숫자의 순서가 다르다고 하더라도, 같은 숫자의 조합을 가지고 있다면 안된다.
값이 원하는 값보다 작으면 오른쪽 값을 옮기고, 크면 왼쪽 값을 옮기는 투포인터 전략을 취해보았다.

*/

/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
const triplets = []
nums.sort((a,b)=>a-b)
for(let i =0;i<nums.length -2 ;i++){
if (i > 0 && nums[i] === nums[i - 1]) continue;
let low = i+1
,high = nums.length -1

while(low < high){
const three_sum = nums[i] + nums[low] + nums[high]
if(three_sum<0){
low +=1
}
else if(three_sum >0){
high -=1
}
else{
triplets.push([nums[i],nums[low],nums[high]])
while (low < high && nums[low] === nums[low + 1]) low++;
while (low < high && nums[high] === nums[high - 1]) high--;
low = low+1
high = high -1
}
}
}
return triplets
};
51 changes: 51 additions & 0 deletions product-of-array-except-self/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
var productExceptSelf = function(nums) {
const n = nums.length;
const left = new Array(n).fill(1);
const right = new Array(n).fill(1);
const answer = new Array(n).fill(1);

// 오른쪽 누적곱
for (let i = n - 2; i >= 0; i--) {
right[i] = right[i + 1] * nums[i + 1];
}

// 왼쪽 누적곱
for (let i = 1; i < n; i++) {
left[i] = left[i - 1] * nums[i - 1];
}

// 최종 곱셈
for (let i = 0; i < n; i++) {
answer[i] = left[i] * right[i];
}

return answer;
};
};
//시간복잡도 O(n)
//공간복잡도 O(n)
// 어려웠던 점: 한번 풀었던 문제지만, 인덱스 범위를 설정하는 점에서 어려움을 겪엇다.


//여기서 공간복잡도를 O(1)로 최적화 할 수 있다. ( 리턴 배열 제외)
/**
* 문제 내에서 Follow up: Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)
*/
var productExceptSelf = function(nums) {
const n = nums.length;
const answer = new Array(n).fill(1);

// 왼쪽 곱
for (let i = 1; i < n; i++) {
answer[i] = answer[i - 1] * nums[i - 1];
}

// 오른쪽 곱 누적하면서 answer에 곱해줌
let right = 1;
for (let i = n - 1; i >= 0; i--) {
answer[i] *= right;
right *= nums[i];
}

return answer;
};
20 changes: 20 additions & 0 deletions valid-anagram/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var isAnagram = function(s, t) {
if (s.length !== t.length) return false;

const map = new Map();

for (let ch of s) {
map.set(ch, (map.get(ch) || 0) + 1);
}

for (let ch of t) {
if (!map.has(ch)) return false;
map.set(ch, map.get(ch) - 1);
if (map.get(ch) < 0) return false;
}

return true;
};

//시간복잡도 : O(n)
//공간복잡도 : O(1) (영문자니까 들어갈 수 있는 수가 한정되어있으므로. )
74 changes: 74 additions & 0 deletions validate-binary-search-tree/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
유효한 BST는 이렇게 정의가 된다.
1. 노드의 좌측 서브 트리에는 노드의 키보다 작은 키를 가진 노드만 있다.
2. 노드의 우측 서브 트리에는 노드의 키보다 큰 키를 가진 노드만 있다.
3. 좌 우측 서브 트리도 모두 이진 탐색 트리여야 한다.

트리의 순회는 재귀로 순회가 가능하다.
또한 BST 의 특성에 맞게, 하위값, 상한값의 개념이 들어간다.
만약 좌측으로 순회하게 될때는
하위값은 부모노드의 하한값.
상한값은 부모노드의 값이 된다.

우측 서브트리로 내려갈 때는,
하위값은 부모노드의 값,
상한값은 부모노드의 상한값이 된다.
*/

/**
* 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
* @return {boolean}
*/
var isValidBST = function(root) {
function dfs(node,low,high){
if(!node) return true; // leaf
if(
(low !==null && node.val <= low)||
(high !== null && node.val >= high)){
return false
}
return dfs(node.left,left,node.val) && dfs(node.right,node.val,high)

}
dfs(root,null,null)
};



/*
2. 두번째로는 중위순회로 해결할 수 있다.
중위순회 : 왼쪽 → 현재 노드 → 오른쪽 순서로 방문하는 방식

이진탐색 트리는 오름차순으로 모든 노드를 방문할 수 있다.
좌측트리를 먼저 순회하고, 부모노드를 방문하고, 그 다음 우측 트리를 순회하기 때문이다.

따라서, 중위순회가 오름차순으로 진행되지 않는다면 이것은 유효한 이진 트리가 아니다.
*/
var isValidBST = function(root) {
let prev = null;

function inorder(node) {
if (!node) return true; //leaf

if (!inorder(node.left)) return false;

//좌측 순회
if (prev !== null && node.val <= prev) return false;
prev = node.val;

return inorder(node.right);
}

return inorder(root);
};
// 둘다 시간복잡도 O(N)이다.
// 공간복잡도 O(h) (재귀 스택만큼)