본문 바로가기
개발/Coding Test

[프로그래머스 LV1] 공원 산책 - Java, Kotlin, Python, Go

by dwony26 2023. 4. 20.
반응형

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

 

프로그래머스

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

programmers.co.kr

 

지나다니는 길을 'O', 장애물을 'X'로 나타낸 공원 배열이 주어질 때, 로봇 강아지가 움직인 위치를 구하는 문제입니다.

장애물을 만나거나 맵을 벗어나면 그 자리에서 멈추는 것이 아니라 명령 자체를 무시합니다.

따라서 한 칸씩 움직이면서 판단하는 것이 아니라 이동 가능 여부를 먼저 판단한 후 가능하면 이동하도록 구현해야 합니다.

또한 시작점이 'S'로 표시되는데 이 곳 역시 이동 가능한 구역입니다. 장애물을 판단할 때 주의합시다.

 

Java

import java.util.stream.IntStream;

class Solution {
    private boolean isMovableX(String[] park, int x1, int x2, int y) {
        return x1 >= 0 && x2 < park[0].length() && IntStream.range(x1, x2 + 1).allMatch(x -> park[y].charAt(x) != 'X');
    }

    private boolean isMovableY(String[] park, int y1, int y2, int x) {
        return y1 >= 0 && y2 < park.length && IntStream.range(y1, y2 + 1).allMatch(y -> park[y].charAt(x) != 'X');
    }
    
    public int[] solution(String[] park, String[] routes) {
        int x = 0, y = 0;
        for (int i = 0; i < park.length; i++) {
            if (park[i].contains("S")) {
                x = park[i].indexOf("S");
                y = i;
                break;
            }
        }

        for (String route: routes) {
            char direction = route.charAt(0);
            int move = route.charAt(2) - '0';
            switch (direction) {
                case 'E' -> { if (isMovableX(park, x, x + move, y)) x += move; }
                case 'W' -> { if (isMovableX(park, x - move, x, y)) x -= move; }
                case 'S' -> { if (isMovableY(park, y, y + move, x)) y += move; }
                case 'N' -> { if (isMovableY(park, y - move, y, x)) y -= move; }
            }
        }

        return new int[] {y, x};
    }
}

S의 위치를 먼저 찾은 후 이동 가능 여부를 판단하여 x, y의 좌표를 변경해 줍니다.

 

Kotlin

class Solution {
    fun isMovableX(park: Array<String>, x1: Int, x2: Int, y: Int) =
        x1 >= 0 && x2 < park[0].length && (x1 .. x2).all { x -> park[y][x] != 'X' }

    fun isMovableY(park: Array<String>, y1: Int, y2: Int, x: Int) =
        y1 >= 0 && y2 < park.size && (y1 .. y2).all { y -> park[y][x] != 'X' }
        
    fun solution(park: Array<String>, routes: Array<String>): IntArray {
        var y = park.indexOfFirst { it.contains('S') }
        var x = park[y].indexOf('S')

        for (route in routes) {
            val direction = route[0]
            val move = route[2].digitToInt()
            when (direction) {
                'E' -> if (isMovableX(park, x, x + move, y)) x += move
                'W' -> if (isMovableX(park, x - move, x, y)) x -= move
                'S' -> if (isMovableY(park, y, y + move, x)) y += move
                'N' -> if (isMovableY(park, y - move, y, x)) y -= move
            }
        }
        
        return intArrayOf(y, x)
    }
}

Kotlin은 Java와 동일한 형태이지만 코드가 더 깔끔합니다.

Java코드와 차이가 없는데 프로그래머스의 문제인지 성능은 더 안 좋게 나옵니다. 

 

Python

def is_movable_x(park, x1, x2, y):
    return x1 >= 0 and x2 < len(park[0]) and all([park[y][x] != 'X' for x in range(x1, x2 + 1)])


def is_movable_y(park, y1, y2, x):
    return y1 >= 0 and y2 < len(park) and all([park[y][x] != 'X' for y in range(y1, y2 + 1)])


def solution(park, routes):
    y = int([y for y, s in enumerate(park) if 'S' in s][0])
    x = park[y].index('S')

    for route in routes:
        direction = route[0]
        move = int(route[2])

        if direction == 'E' and is_movable_x(park, x, x + move, y):
            x += move
        elif direction == 'W' and is_movable_x(park, x - move, x, y):
            x -= move
        elif direction == 'S' and is_movable_y(park, y, y + move, x):
            y += move
        elif direction == 'N' and is_movable_y(park, y - move, y, x):
            y -= move

    return [y, x]

Python 3.10 패턴 매칭이 추가되었지만 프로그래머스는 아직 3.8버전이므로 If로 구분해 줍니다.

Java나 Kotlin보다 좋은 성능을 보여줍니다.

 

Go

import (
	"strings"
)

func isMovableX(park []string, x1 int, x2 int, y int) bool {
	if x1 < 0 || x2 >= len(park[0]) {
		return false
	}
	for x := x1; x <= x2; x++ {
		if park[y][x] == 'X' {
			return false
		}
	}
	return true
}

func isMovableY(park []string, y1 int, y2 int, x int) bool {
	if y1 < 0 || y2 >= len(park) {
		return false
	}
	for y := y1; y <= y2; y++ {
		if park[y][x] == 'X' {
			return false
		}
	}
	return true
}

func solution(park []string, routes []string) []int {
	var x, y int
	for i := 0; i < len(park); i++ {
		if strings.Contains(park[i], "S") {
			x = strings.Index(park[i], "S")
			y = i
			break
		}
	}

	for _, route := range routes {
		direction := route[0]
		move := int(route[2] - '0')
		switch direction {
		case 'E':
			if isMovableX(park, x, x+move, y) {
				x += move
			}
		case 'W':
			if isMovableX(park, x-move, x, y) {
				x -= move
			}
		case 'S':
			if isMovableY(park, y, y+move, x) {
				y += move
			}
		case 'N':
			if isMovableY(park, y-move, y, x) {
				y -= move
			}
		}
	}

	return []int{y, x}
}

역시나 Go는 편의 기능이 없어 코드가 가장 길지만 가장 좋은 성능을 보여줍니다.

반응형

댓글