728x90

https://school.programmers.co.kr/learn/courses/30/lessons/150368?language=javascript

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

function solution(users, emoticons) {
    let answer = [0, 0];

    function discountCombinations(discounts, numProducts) {
    
        function generateCombo(currentCombo, depth) {
            if (depth === numProducts) {
                let plus = 0, sell = 0; //플러스 가입자수, 총 판매금액 
                
                //reduce를 사용해 이모티콘 총 구매금액을 계산 
                for (let user of users) {
                    let total = emoticons.reduce((sum, price, c) => 
                        sum + (currentCombo[c] >= user[0] ? price * (1 - currentCombo                         [c] * 0.01) : 0), 0
                    );
                    //총 구매한 금액이 목표금액보다 비싼경우 구매를 취소하고 플러스 가입 
                    if (total >= user[1]) plus++;
                    else sell += total;
                }
                //그 경우의 수 마다 max값을 비교해서 최적의 결과를 answer에 넣어줌 
                if (plus > answer[0] || (plus === answer[0] && sell > answer[1])) {
                    answer = [plus, sell];
                }
                return;
            }
            //재귀
            for (let discount of discounts) {
                generateCombo([...currentCombo, discount], depth + 1);
            }
        }
        generateCombo([], 0);
        
    }

    discountCombinations([10, 20, 30, 40], emoticons.length);
    return answer;
}

 

재귀함수를 사용해서 각 이모티콘별로 할인되는 모든 경우의 수를 구하고, 그 경우의 수 중 max 값을 찾는 

무식한 방법을 사용했다 ㅎㅎ ... 

이모티콘의 갯수가 많지 않고 할인은 10 20 30 40 단 네가지의 경우의 수만 존재하기때문에 가능했던 풀이 

728x90

https://school.programmers.co.kr/learn/courses/30/lessons/12909

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 
 

function solution(s){
    var answer = true;
    var stack = [];
    
    for(i of s){
        if(i==="(") stack.push(i);
        else{
            if(stack===0)return false;
            else stack.pop(); //stack에는 (만 들어가기때문
        }
    }
    

    return stack.length===0;
}

 
처음엔 스택의 LIFO 개념을 생각해서 push pop을 이용해 이렇게 작성했다. 
그러나 2,6번 케이스에서 오답이 나와서 반례를 찾아헤맸다.....
 
근데 완전 바보짓이었음 헤헷 
stack === 0 이라고 써놔서 오답이 뜬거였다.
 

function solution(s){
    var answer = true;
    var stack = [];
    
    for(i of s){
        if(i==="(") stack.push(i);
        else{
            if(stack.length===0)return false;
            else stack.pop(); //stack에는 (만 들어가기때문
        }
    }
    

    return stack.length===0;
}

 
이렇게 풀면 된다 ~.~ 요즘 스택에대해 공부중이어서 냅다 풀어본 문제 

728x90

 

 

실행 문맥(excution context)이란 코드가 실행되는 동안 필요한 정보를 담고 있는 환경을 말한다. 

함수 선언-실행 과정에서 실행 문맥이 어떻게 생성되는지를 연관지어 생각해보면 이해하기 더 쉽다. 

 

 

이것으로 예시를 들면 

console.log(square(5));

function square(n) {
  return n * n;
}

 

1.  함수 선언 : 함수는 실행되기 전 변수 환경에 저장(메모리 할당)된다.

(square가 메모리에 할당됨)

 

2. 함수 호출 : 함수가 호출되는 이때 새로운 실행 문맥이 생성된다. (call stack에 저장) 또한 함수 내부의 지역변수와 매개변수가 변수 환경에 할당된다. 

(console.log로 호출하는 부분. 여기서는 호이스팅을 사용해 선언 전에 호출했다.)

 

 

함수 호출이 발생하면 새로운 실행 문맥이 생성되고,

이때 함수 내부에서 사용하는 변수와 매개변수가 변수 환경에 저장된다.

 

그다음 함수 내부의 코드가 실행되면서 렉시컬 환경을 기준으로 변수와 값을 검색하고 업데이트하는 과정을 거친다.

이 과정에서 함수 내부에서 필요한 변수는 현재 렉시컬 환경에서 찾고, 현재 환경에 없으면 상위 스코프로 올라가면서 값을 검색한다.

 

3. 함수 실행 종료 : 마지막으로, 함수 실행이 끝나면 생성되었던 실행 문맥이 스택에서 제거되고, 함수와 관련된 변수와 메모리도 해제된다.

 

 

즉, 함수 호출 과정에서는 실행 문맥이 생성되고, 코드 실행을 관리하며, 실행이 종료되면 사라지는 흐름이 반복된다.

~,~

 

console.log(square(5)); 

function square(n) {
  return n * n;
}

위 예제와 같이 함수를 선언전에 사용하는 것을 *호이스팅이라 하고, 이경우엔 에러가 발생하지 않는다.
그러나

console.log(square(5)); //에러 발생!

const square = (n) =>{
  return n * n ; 
}

이렇게 함수를 변수로 선언하여 사용하는 경우에는 변수만 선언되고, 함수내용은 초기화 되지 않기 때문에
선언 전에 호출하면 reference error가 발생한다.

 

만약 비동기 함수의 경우에는? 우선 콜스택에 들어간 다음(실행문맥생성) 작업을 위해 콜스택에서 제거되고 webapi로 보내진다. 작업이 끝나고 큐로 이동된 비동기 함수는 동기함수의 처리가 끝나면 다시 콜스택에 들어가고 다시 새로운 실행문맥이 생성된다. 그리고 실행이 끝나면 콜스택에서 제거된다. 

728x90

자바스크립트의 이벤트루프란, 

스택이 비었을때 콜백 큐(callback queue)에 존재하는 작업(함수)를 스택으로 옮기는것을 말한다. 여기서 쓰이는 스택을 콜 스택(call stack)이라고 한다. 

 

자바스크립트가 싱글 스레드 논 블록킹 언어라는 개념과 헷갈릴 수 있는데 함께 정리해보면 이해가 될 것이다.! 

( 논 블로킹: 하나의 오래 걸리는 작업이 수행되는 동안에도 다른 작업들을 처리 대기 상태에 두고, 완료된 작업을 나중에 처리할 수 있는 방식 )

 

우선 우리가 일반적으로 사용하는 계산이나 조건문, 반복문 등을 동기함수라고 부르는데, 

이런 함수들은 자바스크립트가 만나는 즉시 콜 스택으로 보내며 동기적으로 작업을 처리한다. 그러다 Settimeout, Promise, Http요청과 같은 비동기 함수를 만나게 되면, 이들을 웹api로 전달한 다음,  작업이 끝나면 콜백 큐로 보내 대기하도록 한다.

콜 스택에서 모든 동기 함수를 처리하는 작업이 끝나면, 그다음 자바스크립트는 큐에 있던 비동기 함수를 스택으로 보내 처리한다. 

 

이해하는데 도움되는 예제도 함께 첨부하겠다

 

console.log("1. 콘솔 "); // 동기 -> 콜 스택에서 즉시 처리 됨.

if (true) {
  console.log("2. 조건문 "); // 동기 -> 콜 스택에서 즉시 처리됨.
}

setTimeout(() => {
  console.log("5. setTimeout "); // 비동기 -> 매크로태스크 큐 보냄.
}, 0);

Promise.resolve().then(() => {
  console.log("4. Promise "); // 비동기 -> 마이크로태스크 큐 보냄. 
});

console.log("3. 콘솔 "); // 동기 -> 콜 스택에서 즉시 처리됨.

 

코드상에서는 콘솔 - 조건문 - setTimeout- Promise - 콘솔 순으로 선언되었지만,

실제로 자바스크립트 상에서는 콘솔 - 조건문 - 콘솔 - Promise - setTimeout 순으로 출력될 것이다.  

 

예제에 나와있다시피 비동기 함수 사이에도 처리하는 우선순위가 존재한다. 

마이크로테스크 큐(Promise) 먼저, 그다음 매크로테스크 큐(setTimeout)가 처리된다. 애니메이션 프레임 큐 라는 것도 있는데 이것은 랜더링 주기에 맞춰 실행되므로 앞의 둘과 실행 시점이 다르다.  이것에대해서는 다음 글에서 다시 정리해보겠다! 

 

 

728x90

 

 

정적 타입 검사란 ? 타입스크립트가 기본적으로 제공하는 기능으로,

컴파일 단계에서 변수나 리턴값, 파라미터 등의 타입에러를 찾아주는 것을 말한다. 

 

동적 타입 언어인 javascript는 암묵적 타입 변환 등을 허용하기 때문에 서로 다른 타입간의 계산을 허용하는 경우도 있고,

그로인해 예기치못한 런타임 에러가 발생할 수도 있다. 

 

그러나 타입스크립트는 컴파일시에 모든 변수, 매개변수 등의 정적 타입 검사를 진행하기 때문에, 

런타임시 발생할 에러를 사전에 방지할 수 있다. 

 

 

예를 들어, 

 

자바스크립트의 경우에는 

let num = 30;
let strNum = "2";

let plus = num+strNum;
console.log(plus); // "302" 출력 ;

let minus = num - strNum;
console.log(minus); //28 출력

암묵적 타입 변환을 허용해서 덧셈 연산인 경우, 숫자를 문자열로 변환한 계산을 시도하고, 뺄셈 연산의 경우엔 문자열을 숫자로 바꾸는 것을 시도한다. 

 

그러나 타입스크립트는 위와 같은 암묵적 타입 변환을 허용하지 않고, 코드에서부터 타입 에러를 표시해준다. 

 

또한, 

tsconfig.json 파일을 수정해서 더욱 엄격한 모드로 변경하는 것도 가능하다. (any를 허용하지 않음)

728x90

https://school.programmers.co.kr/learn/courses/30/lessons/340213?language=javascript

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

처음에는 이렇게 풀었다. 

 

function solution(video_len, pos, op_start, op_end, commands) {
    var answer = '';
    const [min, sec] = pos.split(":").map(Number); 
    const [vmin,vsec]= video_len.split(":").map(Number); 
    const [smin,ssec]=op_start.split(":").map(Number); 
    const [emin,esec]=op_end.split(":").map(Number); 
    let [nmin,nsec] = [min,sec];
    const converter = (min,sec)=>min*60+sec;
    for(cmd of commands){        
        if(cmd==="next"){
            if(converter(nmin,nsec)>=converter(smin,ssec)&&converter(nmin,nsec)<=converter(emin,esec)){ 
               [nmin,nsec]=[emin,esec];
            }
                nsec += 10;
                if (nsec >= 60) {
                    nsec -= 60;
                    nmin += 1;
                }
            if(converter(nmin,nsec)>=converter(smin,ssec)&&converter(nmin,nsec)<=converter(emin,esec)){ 
               [nmin,nsec]=[emin,esec];
            }
        }else{
           if (nmin == 0 && nsec < 10) { 
                [nmin,nsec]=[0,0];
            } 
            else if(nsec<10){
                nsec = 60+nsec-10;
                nmin -=1;
            }else nsec = nsec-10;
        }
     
    }
    return nmin.toString().padStart(2, '0')+":"+nsec.toString().padStart(2, '0');
}

 

1,6,7,9,12  총 5개의 케이스에서 틀렸다고 나왔다. 

 

어떤 케이스가 고려되지 않았는지 모르겠어서 질문 게시판을 찾아보니

동영상 길이보다 길어지는 경우를 고려해야 한다고 나와있었다!!!

 

애초에 props로 동영상 길이를 왜 제공해주는지 생각했어야 했는데....ㅎㅎ 나의 실수 

 

그래서 중간에 

 if(converter(vmin,vsec)<=converter(nmin,nsec)) [nmin,nsec]=[vmin,vsec];

이 부분을 추가해 주었는데 어라라 아직도 1번케이스가 통과가 되지 않는 것이었다. 

 

다시 찾아보니 prev 명령어의 경우에도 오프닝 구간안에 있으면 오프닝 끝으로 이동해야한다는 것이었다.........헉 

function solution(video_len, pos, op_start, op_end, commands) {
    var answer = '';
    const [min, sec] = pos.split(":").map(Number); 
    const [vmin,vsec]= video_len.split(":").map(Number); 
    const [smin,ssec]=op_start.split(":").map(Number); 
    const [emin,esec]=op_end.split(":").map(Number); 
    let [nmin,nsec] = [min,sec];
    const converter = (min,sec)=>min*60+sec;
    for(cmd of commands){        
        if(cmd==="next"){
            if(converter(nmin,nsec)>=converter(smin,ssec)&&converter(nmin,nsec)<=converter(emin,esec)) 
               [nmin,nsec]=[emin,esec];
            
                nsec += 10;
                if (nsec >= 60) {
                    nsec -= 60;
                    nmin += 1;
                }
            if(converter(vmin,vsec)<=converter(nmin,nsec)) [nmin,nsec]=[vmin,vsec];
            else if(converter(nmin,nsec)>=converter(smin,ssec)&&converter(nmin,nsec)<=converter(emin,esec)){ 
               [nmin,nsec]=[emin,esec];
            }
        }else{
           if (nmin == 0 && nsec < 10) { 
                [nmin,nsec]=[0,0];
            } 
            else if(nsec<10){
                nsec = 60+nsec-10;
                nmin -=1;
            }else nsec = nsec-10;
            
             if(converter(nmin,nsec)>=converter(smin,ssec)&&converter(nmin,nsec)<=converter(emin,esec)) 
               [nmin,nsec]=[emin,esec]; //여기 이부분을 추가함 
        }
     
    }
    return nmin.toString().padStart(2, '0')+":"+nsec.toString().padStart(2, '0');
}

 

오프닝 구간인지 확인하는 조건문을 prev 에서도 넣어주니 

간단하게 해결이 되었다. ㅎㅎ 

난이도 1이라 시간제한이 빡센 문제는 아닌 듯 하다 

 

끝 ~.~

728x90

https://school.programmers.co.kr/learn/courses/30/lessons/160586

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

function solution(keymap, targets) {
    var answer = [];
    var map = new Map();
    keymap.forEach((keys) => {
    for (let idx = 0; idx < keys.length; idx++) {
      let k = keys[idx];
      if (!map.has(k)) {
        map.set(k, idx + 1);
      } else {
        if (map.get(k) > idx + 1) {
          map.set(k, idx + 1);
        }
      }
    }
  });
    
    targets.forEach((t) => {
    let ans = 0;

    for (let i = 0; i < t.length; i++) {
      if (!map.has(t[i])) {
        ans = -1;
        break;
      } else {
        ans += map.get(t[i]); 
      }
    }

    answer.push(ans); 
  });
    return answer;
}

 

keymap으로 넘어오는 값을 배열로 착각하고 forEach로 풀었더니 초반에 오류가 발생했는데

for 반복문으로 푸니까 바로 해결이 되었다 ㅎㅎ 간단한문제! 

728x90
function solution(begin, target, words) {

    if (!words.includes(target)) return 0;

  
    let queue = [[begin, 0]]; 
    let wordAll = new Set(words); 
    let now = begin;
    let answer = 0;
 
    function findSimilar(word1, word2) {
        let diff = 0;
        for (let i = 0; i < word1.length; i++) {
            if (word1[i] !== word2[i])
                diff++;
            if (diff > 1) return false; 
        }
        return diff === 1; 
    }

  
    while (queue.length > 0) {
        let [current, step] = queue.shift();

      
        if (current === target) return step;

     
        for (let word of wordAll) {
            if (findSimilar(current, word)) {
                queue.push([word, step + 1]); 
                wordAll.delete(word); // 방문한 단어는 Set에서 제거
            }
        }
    }

  
    return 0;
}

아직도 이해가 잘 안 된다.........................

728x90

+ Recent posts