알고리즘 문제 풀기/실수축제

프로그래머스 : 표 병합의 "실수축제" - javascript (배열 객체 참조, 타입비교)

Fo_rdang 2024. 7. 10. 11:54
반응형

내가 왜 그동안 코테 시험중에 

"어? 이게 왜 에러가 나지?" 

"왜 작동을 안하지?"

의문이 들었던 이유를 알게됐다. (네이버 부캠을 통해...) 

 

내가 문제를 푸는동안 js 틀린 문법을 썼었던 것이다. 

교묘 ~ 해서 나 스스로도 모르게... 

 

아이러니하게도 "내가 쓰는 틀린 문법을 뭐가 있을까?" 알려고 하면, 

코테 준비를 하는 과정에서 

내가 끈질기게 해당 문제를 몇시간이고 풀어야 한다. 

그 속에서 마주하는 에러들... 

그 에러들을 해결하면서  js의 문법을 자세히 알게된다. 

 

오늘은 해당 문제를 풀면서 실수 축제를 정리해보자. 

목차는 이렇다. 

 

01. 배열의 객체참조 

02. Set 객체에 대해서 

03. number 타입과 string 타입에 비교에 대해서 

04. 배열의 요소 접근법 

 

01. 배열의 객체참조 

틀린코드

: map의 values는 배열이다. 예를들어 values는 [[1,2],[1,3],[1,4]] 형태가 된다. 

해당 values를 반복문으로 돌면서 value인 [1,2]가 [r,c] 와 같은 값인지 비교하는 코드다. 

 

문제는,,, 

value가 [1,2]이고, 

r이 1, c가 2인경우에도 

[1,2] === [1,2]는 false를 반환한다. 

 

어디 부분이 잘못됐을 까?

const checkMerge = (r, c) => {
  for (let [key, values] of map.entries()) {
    for (let value of values) {
      console.log(value, [r, c], 'checkMerge안');
      if (value == [r, c]) { // 이 부분이 원래 코드에서 문제가 있는 부분입니다.
        console.log([key, values]);
        return [key, values];
      }
    }
  }
  return false;
}

 

이유)

배열은 객체이기 때문에 참조 값이 비교된다. 따라서 배열의 값이 같더라도 참조가 다르기 때문에 "==" 혹은 "==="로는 동등성을 판단할 수 없다. 

 

해결)

배열을 비교할 대는 배열의 값들을 개별적으로 비교해야 한다. 


02. Set 객체 

1번과 같은 배열 비교는 Set객체에 값을 추가할 때도 문제가 됐다. 

let set = new Set();
set.add([1, 2]);
set.add([1, 3]);
set.add([1, 3]);

console.log(set); // Set(3) { [ 1, 2 ], [ 1, 3 ], [ 1, 3 ] }

 

아니,, Set 객체는 중복을 허용하지 않는다며,, 왜 [1,3]을 또 넣어?  

 

이유) 

- Set 객체는 원시 값과 객체를 다룰 때 동작이 다르다. 

  - 원시 값에 대해서는 값 자체를 비교. 

  - 객체에 대해서는 참조값 (메모리 주소)를 비교 

 

따라서, [1,3] 배열은 메모리에서 다른 위치에 저장되어 있기 때문에 다른 값으로 처리. 

 

해결)  문자열로 변환해서 추가하자. 

Set 객체에는 보통 문자열을 넣는 코드를 많이 봤는데 이 이유 때문이였다;;

나는 "배열보다 문자열이 편한가보다..." 했었다..

문자열을 넣자 ~~  

 

03. number 타입과 string 타입 비교

 

아래가 내가 문제를 푼 코드이다. 

두개의 tc만 통과하고 제출할 땐 정확도가 30점정도 밖에 안되는 코드인데,, 

내가 문제를 풀면서 깨달은건,,, 

- 각 숫자들을 비교해줄 때 타입을 신경써줘야 한다는 것이다. 

Number 타입, String 타입을 철저히 비교해줘야 한다. 

 

1. 엄격한 동등연산자 (===)

: 값과 데이터 타입이 모두 같은지를 비교한다. 

if(String(2) === Number(2)) console.log(true) 
else console.log(false) 

// false

 

2. 추상 동등 연산자(==)

: 값을 비교하며, 타입을 강제 변환해서 비교한다. 

if(String(2) == Number(2)) console.log(true) 
else console.log(false) 

//true

 

 

3. 내가 작성한 코드 

function solution(commands) {
    let graph = Array.from({length: 51}).map(() => new Array(51).fill('')); 
    let answer = []; 
    let map = new Map(); 
    let mapIdx = 0; 
    
     const update1 = (r,c,value) => {
         //r과 c는 number 타입이다. value는 string 타입이다. 
         if(checkMerge(r,c)){//해당 위치가 merge된 상태라면 
            let key = checkMerge(r,c); //해당 key 가져와서
             let values = map.get(key)
             for(let i=0; i<values.length; i++){ //해당 value 즉, 모든 위치들에 접근해서 
                 let [cr, cc] = values[i].split('').map(v => +v); //해당 위치에 
                 graph[cr][cc] = value; //값을 변경해준다. 
             }
         }else{
                  graph[r][c] = value; //해당 위치가 merge된 애가 아니라면, 그 값만 바꿔준다. 
         }
 }
    const update2 = (value1, value2) => {
        for(let i=1; i<=50; i++){
            for(let j=1; j<=50; j++){
                if(graph[i][j] === value1){
                  graph[i][j] = value2
            }
        }
       }
    }
    const merge = (r1,c1,r2,c2) => {
        if(r1 === r2 && c1 === c2) return; 
        for(let i=0; i<2; i++){
          let key1 = checkMerge(r1,c1)
          let key2 = checkMerge(r2,c2)
            if(key1){
                map.get(key1).push(`${r2}${c2}`); 
            }else if(key2){
                map.get(key2).push(`${r1}${c1}`); 
            }else{
                mapIdx++; 
                map.set(mapIdx, [`${r1}${c1}`, `${r2}${c2}`]); 
            }
        }
        if(graph[r1][c1] !== '' && graph[r2][c2] !== ''){//값을 둘다 가지고 있음
              graph[r2][c2] = graph[r1][c1]
        }else if(graph[r1][c1] !== '' ){//r1,c1이 값 가지고 있음
            graph[r2][c2] = graph[r1][c1]
        }else if(graph[r2][c2] !== ''){//r2,c2이 값 가지고 있음
            graph[r1][c1] =  graph[r2][c2]
        }
    }
    const unmerge = (r,c) => {
        if(checkMerge(r,c)){
            let key = checkMerge(r,c); 
            let values = map.get(key); 
            for(let i=0; i<values.length; i++){
               if(values[i][0] !== String(r) || values[i][1] !== String(c)){
                 let [dr,dc] = values[i]; 
                 graph[dr][dc] = ''
            }
        }
                map.delete(key);       
        }
    }
    const print = (r,c) => {
        if(graph[r][c] !== ''){
             answer.push(graph[r][c])     
        }else{
            answer.push('EMPTY')
        }
    }
    const checkMerge = (r,c) => {
        //r과 c는 number 타입이다. 
        for(let [key, values] of map.entries()){
            for(let value of values){
                if(value.includes(`${r}${c}`)){
                    return key
                }
            }
        }; 
       return false; 
    }
    
    for(let command of commands){
        let com = command.split(' ')[0]
        switch(com){
            case "UPDATE":
               let n= command.split(' ').length; 
                if(n === 4){
                 let [r, c, value] =  command.split(' ').slice(1); 
                    update1(Number(r),Number(c),value)
                }else{
                 let [value1, value2] =  command.split(' ').slice(1);
                    update2(value1, value2); 
                }
                break;  
            case "MERGE":
                let [r1, c1, r2, c2] = command.split(' ').slice(1).map(v => +v)
                merge(r1, c1, r2, c2)
                break; 
            case "UNMERGE":
                let [r,c] = command.split(' ').slice(1).map(v => +v); 
                unmerge(r,c)
                break; 
            default:
                let [i,j] = command.split(' ').slice(1).map(v => +v); 
                print(i,j)
                break; 
        }
    }
    return answer; 
}

 

04. 배열의 요소 접근법 

 

자바스크립트 배열 접근시 문자열로 인덱스를 사용해서 접근하는 것이 가능하다. 

 

- 배열이 기본적으로 객체로 구현되어 있기 때문이다. 

- 숫자 인덱스로 접근하는 것이 더 직관적이고, 성능 면에서 좋긴함

- 배열이 객체로 구현된다는 것은 배열이 일반적인 객체와 동일한 속성을 가지고 있다는 것을 의미함. 

- 객체 속성에 접근할 때 `점 표기법(obj.property)`이나 `대괄호 표기법(obj['property'])`을 사용할 수 있다. 

 

let obj = {
    key: 'value'
};

console.log(obj.key); // 'value'
console.log(obj['key']); // 'value'
반응형