본문 바로가기

알고리즘/프로그래머스

프로그래머스 - 조이스틱(level 2)//Wanna Be 컴잘알

728x90

문체 출처 - https://programmers.co.kr/learn/courses/30/lessons/42860#

 

코딩테스트 연습 - 조이스틱 | 프로그래머스

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다음 알파벳 ▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로) ◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서) ▶ - 커서를 오른쪽으로 이동 예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다. - 첫 번째 위

programmers.co.kr

-문제-

 

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다.
ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA

 

조이스틱을 각 방향으로 움직이면 아래와 같습니다.

▲ - 다음 알파벳 ▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로) ◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서) ▶ - 커서를 오른쪽으로 이동

 

예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다.

- 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다. - 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다. - 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다. 따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.

만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.

 

-접근법-

 

처음엔 접근을 현재 인덱스에서 왼쪽,오른쪽방향으로 갔을때 'A'가 아닌 문자를 더 빨리 만날 수 있는 방향으로 계속 스캔해가는 방식으로 코드를 작성하였다. 이렇게 만드니 마지막 TestCase에서 계속 오류가 발생하였는데 실제 질문 게시판에도 나와 같은 사람들이 매우매우 많았다. 

 

반례를 생각해보니 "AZAAAZ" 가 한쪽방향으로 진행한다면 답이 7이나온다.  그러나 현재 인덱스에서 탐색을 새로 하여 가장 가까운 'A'가 아닌 문자로 찾아가는 방식으로 하면 답이 5가 나온다.

 

정리를 하자면 고려해야할 점은 2가지이다.

1. 현재인덱스에서 'A'가 아닌 가장 가까운 인덱스를 방문해 가면된다.

2. 'Z'인 경우 'A'에서 아래로 1번만 움직이면된다.

 

-후기-

 

Scan 방식 중에 SSTF 스케줄링(Shortest Seek Time First)처럼 하면 됐던거를 잘 못 생각하여 C-SCAN 스케줄링 방식으로 하였다. 처음 방향을 잘못 잡다보니까 예외를 찾는데 까지 오래 걸렸던 것 같다.

 

-코드-

#include <string>
#include <vector>
#include <iostream>
#include <string.h>
using namespace std;

bool check[20];
int result;

vector<int> serach_next(string name,int cur_index) {
	vector<int> v;
	
	int right_cnt = 0;
	int right_index = 0;
	int flag = 0;
	
	for (int i = 0; i < name.length();i++) {
		int index = (i + cur_index)%name.length();
		if (name[index] != 'A' && !check[index]) {

			right_index = index;
			flag = 1;
			break;
		}
		right_cnt += 1;
	}

	int left_cnt = 0;
	int left_index = 0;
	for (int i = 0; i < name.length(); i++) {
		int index = (cur_index-i);
		if (index < 0) {
			index = name.length() + index;
		}

		if (name[index] != 'A' && !check[index]) {
			left_index = index;
			flag = 1;
			break;
		}
		left_cnt += 1;
	}

	if (right_cnt > left_cnt) {
		v.push_back(0);//왼쪽
		v.push_back(left_cnt);
		v.push_back(flag);
		return v;
	}
	else {
		v.push_back(1);//오른쪽 
		v.push_back(right_cnt);
		v.push_back(flag);
		return v;
	}
}

int right_move(string name, int cur_index,int move_cnt, int dir){
	int next_index = 0;
	result += move_cnt;
	
	next_index = (cur_index + move_cnt) % name.length();
	

	if (name[next_index] <= 'N') {
		result += int(name[next_index] - 'A');
	}
	else {
		result += 1;
		result += int('Z' - name[next_index]);
	}

	check[next_index] = true;
	return next_index;
}

int left_move(string name, int cur_index, int move_cnt, int dir) {
	int next_index = 0;
	result += move_cnt;
	
	if (cur_index - move_cnt<0) {
		next_index = name.length() + (cur_index - move_cnt);
	}
	else {
		next_index = (cur_index - move_cnt);
	}
	
	if (name[next_index] <= 'N') {
		result += int(name[next_index] - 'A');
	}
	else {
		result += 1;
		result += int('Z' - name[next_index]);
	}

	check[next_index] = true;
	return next_index;
}

int solution(string name) {
	memset(check, false, sizeof(check));

	for (int i = 0; i < name.length(); i++) {
		if (name[i] == 'A') {
			check[i] = true;
		}
	}
	result = 0;
	int cur_index = 0;

	if (name[cur_index] <= 'N') {
		result += int(name[cur_index] - 'A');
	}
	else {
		result += 1;
		result += int('Z' - name[cur_index]);
	}
	check[cur_index] = true;

	while (1) {
		vector<int> v;
		//현재인덱스에서 가장 가까운 'A'아닌 문자를 찾는 함수
		v = serach_next(name, cur_index);
		int dir = v[0];// 1이면 오른쪽, 0이면 왼쪽
		int move = v[1]; //이동 횟수
	
		
		if (!v[2]) { // 모두 다 'A'이거나 이미 다 방문했음
			break;
		}

		if (dir) { //오른쪽이동
			cur_index = right_move(name,cur_index,move, dir);
		}
		else { //왼쪽이동
			cur_index = left_move(name,cur_index,move, dir);
		}

	}

	return result;
}
728x90