깊은바다거북
개발 공부 기록
깊은바다거북
전체 방문자
오늘
어제
  • 분류 전체보기 (219)
    • JAVA (9)
    • JavaScript (15)
    • 스파르타코딩클럽 (11)
      • [내일배움단] 웹개발 종합반 개발일지 (5)
      • [내일배움캠프] 프로젝트와 트러블 슈팅 (6)
    • SQL | NoSQL (4)
    • CS 등등 (0)
    • TIL | WIL (173)
    • 기타 에러 해결 (3)
    • 내 살 길 궁리 (4)

인기 글

최근 글

최근 댓글

태그

  • 자잘한 에러 해결
  • 자바스크립트 기초 문법
  • 최소 힙(Min Heap)
  • 재귀 함수
  • Leetcode
  • Binary Tree(이진 트리)
  • 팀 프로젝트
  • TIT (Today I Troubleshot)
  • Linked List
  • 혼자 공부하는 자바스크립트
  • BST(이진 탐색 트리)
  • 01. 미니 프로젝트
  • tree
  • Trie
  • DFS(깊이우선탐색)
  • 코딩테스트 연습문제
  • Preorder Traversal(전위 순회)
  • BFS(너비우선탐색)
  • 프로그래머스
  • leetcode-cli
  • Backtracking(백트래킹)
  • Til
  • 자료 구조
  • 트러블 슈팅 Troubleshooting
  • 시간 복잡도
  • TypeScript
  • 점화식(Recurrence Relation)
  • Inorder Traversal(중위 순회)
  • POST / GET 요청
  • 최대 힙(Max Heap)
hELLO · Designed By 정상우.
깊은바다거북

개발 공부 기록

TIL | WIL

2/21 화 (이론 정리 없이 코딩만 한 하루) TIL

2023. 2. 22. 00:09

(막간 보충 공부중)

오늘 한 일

  • 프로그래머스 30분 - 옹알이(1)
  • 프로그래머스 30분 - 특정 문자 제거하기
  • 푼 문제 코드 리뷰 및 리팩토링
  • ‘여태 푼 문제 파일 중 랜덤으로 불러오기’ 프로그램 구상 및 개발 중 - fs 모듈 공부중


특정 문자 제거하기

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

문자열 replaceAll 이용

function solution1(my_string, letter) {
	return my_string.replaceAll(letter, '');
}

배열 이용

// replaceAll 없이
function solution2(my_string, letter) {
	return my_string.split(letter).join('');
}

배열 내장 함수 없이 (내장 함수를 쓰지 않은 이 방식이 코딩 테스트에서는 가장 좋다...)

function solution3(my_string, letter) {
	let newStr = ''
	for (let char of my_string) { 
		if (char !== letter) {
			newStr += char;
		}
	}
	return newStr;
}

정규식 이용:

// RegExp으로
function solution4(my_string, letter) {
	// 1. 'haha'에서 모든 a를 매치하고 싶다:
	// const regex = /a/g; // haha => hh

	// 2. 문자열 a 말고 모든 변수 letter를 매치하고 싶다:
	// const regex = new RegExp(`${letter}/g`)

	// 3. new RegExp로 만들 때엔 슬래시(/)를 빼야 함. => 그러면 g나 i같은 플래그는 어떻게? => 제 2의 인수로 넣어주면 됨: 
	// const regex = new RegExp(letter, 'g');

	const re = new RegExp(letter, 'g');
	return my_string.replace(re, '');
}

배운 점:

  • 정규식에서, /ha/g는 new RegExp(’ha’, ‘g’) 와 같다. (플래그를 2번째 인수로 보내줌)
  • 정규식에서, 변수를 패턴으로 받으려면 /ha/g 방식으로는 안되고 객제 선언 방식으로 해줘야 한다 :
    const letter = 'ha';
    const regex = new RegExp(letter, 'g');

옹알이 (1)

(혼자) 처음에 푼 방식:

function solution1(babblingArray) {
    const possibles = ["aya", "ye", "woo", "ma"];
    let count = 0;
    for (let i = 0; i < babblingArray.length; i++) {
        let word = babblingArray[i];
        word = word.replace("aya", " ")
                .replace("ye", " ")
                .replace("woo", " ")
                .replace("ma", " ")
                .trim();
                if (word === "") {
                    count++;
                }
            }
    return count;
}

⇒ possibles를 사용하지 않고 있다. 나중에 할 수 있는 옹알이가 더 많아지게 될 때를 대비해 .replace()를 계속 추가해야 하는 지금의 상황보다 possibles 객체를 이용해 거기에만 추가해도 되게끔 만드는 것이 좋겠다.

⇒ 또 replace를 한 번 할 때마다 O(N)을 한 번 도는 것과 같다. 사실 nO(N)은 O(N)과 같다고 취급되므로 별 문제는 없지만, 그래도 replace를 네 번, 다섯번 돌게 되는 것을 방지할 수 있다면 더 좋을 것이다.

(Mob programming으로) 리팩토링 이후:

const POSSIBLES = ["aya", "ye", "woo", "ma"];
function solution(arr) {
    let count = 0;
    
    arr.forEach((word) => {
        let j = 0;
        let k = 0;

        while (k !== word.length) {
            const subString = word.slice(j, k + 1);

            if (POSSIBLES.includes(subString)) {
                // console.log(subString, " is a valid babble");
                j = k + 1;
                k = k + 1;
            } else {
                k++;
            }
        }

        if (j === k) {
            count++;
        }
    });
    
    return count;
}

배운 점:

  • Sliding Window 기법 : 루프 한 번에 인덱스 두 개를 놀리는 방식. 코테용 풀이법으로 좋다. 중상 정도의 풀이 점수를 받을 수 있을 것임.

    ⇒ 사실 sliding window 테크닉은 ‘같은 대상을 순회할 때’, 2중 for문을 만들 것을 단일 for문으로 만들 수 있는 기법이라 사용되는 것이다. 이 문제같은 경우엔 순회해야 하는 대상이 가능한 발음 POSSIBLES와 주어진 옹알이 arr로 서로 달라, 결국 둘 다 검사하려면 nested 반복문이 될 수밖에 없는 구조이다. sliding window 테크닉을 쓴다고 하더라도 효용이 없어지게 되는 것이다. 시간복잡도로 따지면 forEach 문 안에 다시 while문이 있으므로 이중 for문, O(N^2)이게 되는 것은 sliding window 방식을 사용하지 않은 풀이와 같게 된다. 다만 sliding window라는 기법을 연습해 볼 수 있었다는 데에 의의를 두자.

Sliding Window 테크닉을 쓸 수 있는 문제는?

문제에서 객체나 배열, 문자열같이 iterable한 데이터 타입이 주어지고 다음과 같은 리턴값을 요구하는 경우:

  1. Minimum value
  1. Maximum value
  1. Longest value
  1. Shortest value
  1. K-sized value

‘연속된’이라는 키워드가 들어가는 경우.

ex) 주어진 숫자 배열에서, 연속된 두 개의 숫자 쌍 중 합이 가장 큰 쌍을 배열로 반환하기. ⇒ 2-sized value와 maximum value가 모두 요구되는 케이스.

ex) 주어진 문자열에서, 중복된 문자가 없는 가장 긴 부분 문자열(=연속됨)의 길이를 찾기. ⇒ longest value를 요구하는 케이스.

(참조: https://levelup.gitconnected.com/an-introduction-to-sliding-window-algorithms-5533c4fe1cc7)

매일 품새를 연습하기 위해 ‘여태 푼 문제 파일 중 하나를 랜덤으로 불러와주는 프로그램’을 만들고 싶다 (미완)(구상중):

FS

동기와 비동기. 모든 비동기 메소드는 뒤에 ‘Sync’를 달고 있는 형제 동기 메소드가 있다.

예: fs.writeFile() 과 fs.writeFileSync().

파일을 처리하는 데 항상 시간이 걸릴 것이라 감안하여 언제나 비동기 메소드(Sync가 안 붙은)를 써주고 콜백으로 완료 처리를 부탁하도록 하자.

기본 CRUD 메소드:

fs.writeFile(), fs.readFile(), fs.unlink()

구현해야 하는 workflow:

  • 부분 파일명으로 특정 파일 찾기 ⇒ readdir() / read() / readFile() / exists() /
  • 찾은 파일에서 ‘주석’부분까지만 읽어들이기 ✔️
  • 부분 파일명으로 찾은 특정 파일의 이름에서 넘버링 따오기 ⇒ fsPromises.readdir()의 .name속성 /
  • +1 해서 새 파일명으로 삼아 새 파일 만들고
  • 찾은 ‘주석’ 부분을 써넣기.
  • 저장하기(어디에?)
  • 방금 만든 새 파일 편집기로 열어두기.

  • 아니다. …각 kata 파일들은 테스트 코드와 소스 코드가 한 쌍씩만 있는 게 더 깔끔하고 좋으려나…

    한 파일 안에 날짜 구분해서 몽땅 집어넣기의 장단점:

    장: 폴더 관리가 깔끔해진다.

    단: 파일 하나의 구조가 지저분해진다. 어떻게 새롭게 푼 부분을 구분해 넣을 것인가?

    ⇒ 음. 크게 달라진 날과 날의 코드마다 마일스톤처럼 기록으로 남겨두고, 그게 그거같이 비슷비슷하게 풀린 코드는 풀고서 이전 코드를 삭제하는 식으로?

    ⇒ 날짜와 날짜의 구분은 그냥 /* 2023. 02. 20 (월) */ 같이 주석으로 간단히 표시하자.

    여러 파일을 만들 때의 장단점:

    장: 디렉토리 목록을 보고 얼마나 여러 번 반복해서 풀었는지 한 눈에 볼 수 있다. (푼 횟수만큼 파일이 생성되었을 테니) ⇒ 파일명 끝에 반복 횟수를 매번 업데이트 하는 방법으로 대체할 수 있을 것 같다.

    단: 너무 많은 파일이 생성된다. 나중에는 오히려 디렉토리 구조로 한 눈에 파악하기가 더 힘들어지게 된다.

    생각하다보니 여러 파일을 만드는 것은 단점이 너무 크다는 결론이 났다.

    하지만 파일 모듈을 다루는 연습을 위해 한 번 원래의 계획대로 만들어보는 것도 나쁘지 않을 듯? 일단 ‘새 파일명으로 편집기를 여는 것’까지는 하고, 저장하지 않고 파괴하면 되잖아.


Uploaded by N2T

    'TIL | WIL' 카테고리의 다른 글
    • 2/23 목 (지지부진해서 미안해) TIL
    • 2/22 수 (뜬금없이 “RFC” 문서 조직 연구) TIL
    • 2/20 월 (튜터를 모신 코드 리뷰와 리팩토링의 달콤함) TIL
    • 2/17 금 (Rule of Three 중복 제거 리팩토링, 생생한 예제 코드가 여기있다) TIL
    깊은바다거북
    깊은바다거북

    티스토리툴바