코드카타 - week2_11.07~11.11

송철진·2022년 11월 6일
0

코드카타

목록 보기
2/11

day 1(11.07)

로마자에서 숫자로 바꾸기
1~3999 사이의 로마자 s를 인자로 주면 그에 해당하는 숫자를 반환해주세요. 로마 숫자를 숫자로 표기하면 다음과 같습니다.

SymbolValue
I1
V5
X10
L50
C100
D500
M1000

로마자를 숫자로 읽는 방법은 로마자를 왼쪽부터 차례대로 더하면 됩니다.
III = 3 XII = 12 XXVII = 27 입니다.
IV = 4 (IIII가 아님!) 뒤의 숫자에서 앞의 숫자를 빼주면 됩니다. 9는 IX입니다.
I는 V와 X앞에 와서 4, 9
X는 L, C앞에 와서 40, 90
C는 D, M앞에 와서 400, 900

소스코드

function romanToNum(s) {
  let str = s;
  let result = 0;
  let sum = 0;
  const arr = ["IV", "IX", "XL", "XC", "CD", "CM"];
  for(let i=0; i<arr.length;i++){
    if(str.indexOf(arr[i]) !== -1){
      str = str.split(arr[i]).join("");
      result += romanObj[arr[i]];
    }  
  }
  
  let strArr = str.split("").map(el => romanObj[el]);
  for(let i of strArr){
    sum += i;
  }
  
  return result + sum;
}

const romanObj = {
  "I": 1,
  "V": 5,
  "X": 10,
  "L": 50,
  "C": 100,
  "D": 500,
  "M": 1000,
  "IV": 4,
  "IX": 9,
  "XL": 40,
  "XC": 90,
  "CD": 400,
  "CM": 900
}

풀이:

  1. 변수str = 입력받은인자s 를 선언, 할당
  2. 객체romanObj = {"로마숫자":숫자}를 선언
    배열arr = [4,9,40,90,400,900] 에 대한 로마숫자를 선언
  3. (반복) arr의 요소가 있나요?
  • Y : 요소를 romanObj의 키로 접근해서 값을 반환하고 result(초기값 0)에 더한다
    str에서 arr의 요소를 제외한 문자열을 str에 재할당한다
  • N : i++, 다음 반복을 실행
  1. 나머지 문자열str을 글자단위로 쪼개서 배열로 만들고
    그 배열의 요소를 romanObj의 키로 접근해서 값을 매핑한다
  2. sum(초기값 0)에 4.의 배열의 요소를 모두 더한다
  3. result + sum을 최종 return 한다 (끝)

day 2(11.08)

숫자로 이루어진 배열인 nums를 인자로 전달합니다.
숫자중에서 과반수(majority, more than a half)가 넘은 숫자를 반환해주세요.

예를 들어,
nums = [3,2,3] 👉 return 3
nums = [2,2,1,1,1,2,2] 👉 return 2

가정
nums 배열의 길이는 무조건 2개 이상

function moreThanHalf(nums) {
  // 요소의 중복 수를 키-값으로 생성하는 함수a 
  function a(nums){
  	let obj = {};
    for(let j of num2){  
      obj[j]=0;
      for(let i in nums){ 
        if(nums[i] === j){ 
          obj[j] += 1;  
        }
      }
    }
    return obj;
  }
    
  let num2 = [...new Set(nums)];
  
  for(let i of num2){
    if(a(nums)[i]>nums.length/2){
      return i;
    }
  }
}

아직 이해하지 못한 풀이1(참조 출처)

// 요소의 중복 수를 키-값으로 생성하는 함수a
const a = (arr) => arr.reduce( 
  (ac, v) => ({ ...ac, [v]: (ac[v] || 0) + 1 }), {}
);

TIL
숫자배열 nums를 인자로 받아 nums의 요소() - 중복개수() 형태의 객체를 반환하는 함수를 아래와 같이 짰는데 왜 안될까?

  function a(nums){
  	let obj = {};
    for(let j of num2){
      for(let i in nums){
        obj[j]=0;
        if(nums[i] === j){
          obj[j] += 1;  
        }
      }
    }
  }

👉 1. return obj를 하지 않았다
2. 초기값 설정 obj[j]=0 을 for문(let i) 밖에 두어야 하는데 안에 두어서 합산이 되지 않고 계속 1로 유지됨.

day 3(11.09)

s는 여러 괄호들로 이루어진 String 인자입니다. s가 유효한 표현인지 아닌지 true/false로 반환해주세요.

종류는 '(', ')', '[', ']', '{', '}' 으로 총 6개 있습니다. 아래의 경우 유효합니다. 한 번 괄호를 시작했으면, 같은 괄호로 끝내야 한다. 괄호 순서가 맞아야 한다.

예를 들어 아래와 같습니다.

s = "()"
return true
s = "()[]{}"
return true
s = "(]"
return false
s = "([)]"
return false
s = "{[]}"
return true
s = "[]{}"
return true

풀이
(1) i=0이므로 이하의 조건문을 반복한다
(2) s에 arr[0]인()가 있는가? (3) 있다면 ()를 기준으로 split하고 join하고 i=0으로 초기화한다

"({}[()])" 👉 ["({}[", "])"] 👉 "({}[])"

(2) s에 arr[0]인()가 있는가? (4) 없다면 i=1 이 된다
(2) s에 arr[1]인{}가 있는가? 있다면 {}를 기준으로 split하고 join하고 i=0으로 초기화한다

"({}[])" 👉 ["(", "[])"] 👉 "([])"

(2) s에 arr[0]인()가 있는가? (4) 없다면 i=1 이 된다
(2) s에 arr[1]인{}가 있는가? (4) 없다면 i=2 가 된다
(2) s에 arr[2]인[]가 있는가? (3) 있다면 []를 기준으로 split하고 join하고 i=0으로 초기화한다

"([])" 👉 ["(",")"] 👉 "()"

(2) s에 arr[0]인()가 있는가? 있다면 ()를 기준으로 split하고 join하고 i=0으로 초기화한다

"()" 👉 ["",""] 👉 ""

(2) s에 arr[0]인()가 있는가? (4) 없다면 i=1 이 된다
(2) s에 arr[1]인{}가 있는가? (4) 없다면 i=2 가 된다
(2) s에 arr[2]인[]가 있는가? (4) 없다면 i=3 이 되어 while문을 빠져나온다
(5) s가 ""이라면 true, 아니라면 false를 반환한다

"" 👉 true
function isValid(s){
  const arr = ['()', '{}', '[]'];
  let i=0;
  while(i<arr.length){	// (1)
    if(s.indexOf(arr[i]) !== -1){	// (2)
      s = s.split(arr[i]).join("");	// (3)
      i=0;	
    }else{
      i++;	// (4)
    }
  }
  return s === "" ? true : false;	// (5)
}

TIL
논리적 순서와 조건은 비교적 쉽게 생각해냈는데 for문으로는 도저히 구현할 방법이 생각나지 않아서 한참을 고민했다. arr의 요소가 존재하면 0번 요소부터 다시 비교하도록 해야했는데 재귀함수를 써보려다가 무한루프가 발생해서 runJS 프로그램이 먹통이 되기도 했다. 결과적으로 아직은 암산보다는 종이에 동작 순서와 중간 결과를 직접 그려가면서 다시 검토하는 것이 문제해결하기에 편하다.

원래 재할당할 그릇으로 변수v를 별도로 선언했었는데 매개변수s에 재할당할 수 있다!

day 4(11.10)

nums는 숫자로 이루어진 배열입니다. 가장 자주 등장한 숫자를 k 개수만큼 return해주세요.

nums = [1,1,1,2,2,3]
k = 2
return [1,2]

nums = [1]
k = 1
return [1]

풀이
(1) nums를 받아 같은 숫자끼리 모이도록 정렬, 재할당한다

[1,2,1,2,2,3] 👉 [1,1,2,2,2,3]

(2) nums의 인접한 요소가 서로 다르면 그자리에 콤마(',')을 삽입한다

[1,1,2,2,2,3] 👉 [1,1,',',2,2,2,',',3]

(3) nums를 join해서 string으로 만들고 다시 콤마(,)를 기준으로 split하고 각 요소의 길이를 비교해서 내림차순으로 정렬한다

[1,1,',',2,2,2,',',3] 
👉 "11,222,3" 
👉 ["11", "222", "3"]
👉 ["222", "11", "3"]

(4) 인덱스i는 인자k보다 작다는 조건 하에 반복해서 nums[i]의 첫번째 글자를 숫자형식으로 result[i]에 할당한다

k=2일 때; nums=["222", "11", "3"] 👉 result=[2,1]
function topK(nums, k){
  nums = nums.sort(); // (1)
  let result = [];
  
  for(let i=0; i+1<nums.length; i++){ // (2)
    if(nums[i]!==nums[i+1]){
      nums.splice(i+1, 0, ',');
      i++;
    }
  }
  
  nums = nums.join("").split(',').sort( // (3)
    function compareNumbers(x,y){
    	return y.length-x.length;})
  
  for(let i=0; i<k; i++){	// (4)
    result[i] = Number(nums[i][0]);
  }
  
  return result;
}

TIL
1. 구글링을 통해 sort() 메소드의 괄호 안에 함수를 선언해서 조건에 맞게 재배열할 수 있다는 것을 알았다. 참조

// 배열을 오름차순으로 정렬하는 sort()의 내부 함수
function compareNumbers(a, b) {
  return a - b;
}
  1. string타입으로 선언된 변수a에 대해 배열처럼 a[i]라고 쓰면 string의 i번째 글자에 접근할 수 있다

그리고 더 쉬운 방법이 있을 거 같다..

다른풀이 - [김호준 님]

function topK(nums, k) {
  const getElCount = (nums) => nums.reduce((ac, v) => ({ ...ac, [v]: (ac[v] || 0) + 1 }), {});
  const test = getElCount(nums);
  
  let testarr = Object.values(test)
  
  testarr.sort(function(a, b) { return b - a })
  function getKeyByValue(obj, value) {
    return Object.keys(obj).find(key => obj[key] === value);
  }
  let result = testarr.slice(0, k)
  
  let xarr = []
  for (let i = 0; i < result.length; i++) {
    xarr.push(Number(getKeyByValue(test, result[i])))
  }
  return xarr
}

day 5(11.11)

인자인 height는 숫자로 이루어진 배열입니다. 그래프로 생각한다면 y축의 값이고, 높이 값을 갖고 있습니다.
아래의 그래프라면 height 배열은 [1, 8, 6, 2, 5, 4, 8, 3, 7] 입니다.
저 그래프에 물을 담는다고 생각하고, 물을 담을 수 있는 가장 넓은 면적의 값을 반환해주세요.

가정
배열의 길이는 2이상입니다.

  1. 배열height의 왼쪽 기둥의 위치를 i
  2. 배열height의 오른쪽 기둥의 위치를 j
  3. 밑변 = j-i 이다
  4. 높이 = height[i], height[j] 중 작은 값이다
  5. 넓이 = 밑변*높이 이므로 모든 넓이의 경우의 수를 구해서 배열에 넣고
  6. 오름차순으로 정렬해서
  7. 0번째 값을 리턴한다
function getMaxArea(height) {
  let arr = [];
  for (let i = 0; i < height.length; i++) {
    let 왼쪽 = i;
    let 왼값 = height[i];
    for (let j = i + 1; j < height.length; j++) {
      let 오른쪽 = j;
      let 오값 = height[j];
      function smaller(a,b){return a <= b ? a : b}
      arr.push((오른쪽 - 왼쪽) * smaller(왼값,오값));
    }
  }
  return arr.sort(function(a, b) { return b - a; })[0];
}

👉 정리

function getMaxArea(height) {
  let arr = [];
  for (let i = 0; i < height.length; i++) {
    for (let j = i + 1; j < height.length; j++) {
      function smaller(a,b){return a <= b ? a : b}
      arr.push((j - i) * smaller(height[i],height[j]));
    }
  }
  return arr.sort(function(a, b) { return b - a; })[0];
}

TIL
if(왼값 <= 오값) 에서 <=<==로 쓰면

Uncaught SyntaxError: Unexpected token '='

라고 뜨는데 이유를 모르겠다..
👉 참조 비교연산자에 <== >==은 없다.
크거나 같다(>=), 작거나 같다(<=)는 '='을 한번만 쓴다!

다른 풀이: 김동기-오주형 님

function getMaxArea(height) {
  let size=0;
  for (let i = 0; i < height.length; i++) {
    for (let j = i + 1; j < height.length; j++) {
      size = Math.max(Math.min(height[i],height[j])*(j-i), size)
    }
  }
  return size;
}
console.log(getMaxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]))

for문을 이용해 나올 수 있는 면적의 경우의 수를 다 따진다는 논리는 동일하나 Math함수를 이용해 더 간단하게 풀 수 있는 방법이다

profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글