-
7주차 프로그래머스 레벨2 풀기(조이스틱 문제/숫자 야구/라면공장)old/Algorithm 2020. 7. 25. 18:30728x90
소감
7주차인데 아직도 공부하는 중이다! 꽤 꾸준히 하는 내 자신이 사랑스럽네~
조이스틱 문제
#include <string> #include <vector> #include <iostream> #include <algorithm> #include <limits.h> using namespace std; int solution(string name) { int answer = INT_MAX; // cout << name[0] << ", " << name << "\n"; // char temp = min(name[0]-'A', 1 + 'Z' - 'A'); // cout << name[0]-'A' << ", " << 1 + 'Z' - name[0]; char updown = min(name[0]-'A', 1 + 'Z' - name[0]); string aa = ""; int ac = 0; for(int i = 0; i < name.size(); i++){ aa += "A"; if(name[i] != 'A') ac++; } for(int i = 0; i < name.size(); i++){ int cur = 0; int c = 0; // i번째까지 계산하고 왼쪽으로 이동 for(int j = 0; j <= i; j++){ if(j != 0){ cur++; } if(name[j] != 'A'){ c++; cur += min(name[j]-'A', 1 + 'Z' - name[j]); } if(c == ac){ break; } } if(c == ac){ if(answer > cur) answer = cur; continue; } cur += (i); for(int j = name.size() - 1; j > i; j--){ cur++; if(name[j] != 'A'){ c++; cur += min(name[j]-'A', 1 + 'Z' - name[j]); } if(c == ac){ break; } } if(answer > cur) answer = cur; } // int c = 0; // int tright = 0; // //다 오른쪽으로 // for(int i = 0; i < name.size(); i++){ // if(i != 0){ // tright++; // } // if(name[i] != 'A'){ // c++; // tright += min(name[i]-'A', 1 + 'Z' - name[i]); // } // if(c == ac){ // break; // } // } // c = 0; // int tleft = 0; // //다 왼쪽으로 // if(name[0] != 'A'){ // c++; // tleft += min(name[0]-'A', 1 + 'Z' - name[0]); // } // for(int i = name.size() - 1; i > 0; i--){ // tleft++; // if(name[i] != 'A'){ // c++; // tleft += min(name[i]-'A', 1 + 'Z' - name[i]); // } // if(c == ac){ // break; // } // } // cout << tright << ", " << tleft; // answer = tright; // if(answer > tleft){ // answer = tleft; // } return answer; }
뒤에 주석부분은 남겨둔 이유가 노가다로 하나하나 다 코딩을 하려다가 곰곰히 생각해보니까 반복문으로 브루트포스적으로 해결할 수 있다는 깨달음이 왔기때문이다. 생각을 하고 코딩을 하는게 좋은 습관이지만, 코딩하다가 보면 좋은 생각이 떠오르기도 하는 법
문제 풀이를 해결한 방법은 요약하면
1. 조건에서 문자열 길이가 20밖에 안됨 -> 뭔가 반복문으로 대충 처리해도 효율성이나 그런건 전혀 문제가 안된다
2. 각 문자에서 조이스틱을 계산하는 건 굉장히 쉽다.
min(name[j]-'A', 1 + 'Z' - name[j])
이게 다다. 위로 갔을때 아래로 갔을때를 비교만 하면된다.
3. 좌우로 가는게 나는 좀 골때린다고 생각했는데, 문자열 길이가 20밖에 안되고, 방향은 한번밖에 못꺽는다.
오른쪽으로 가다가 왼쪽으로 가다가 다시 오른쪽으로가면 최소길이가 될수 없기에(오른쪽으로 쭉가는거보다도 효율이 없다)
-> 즉, 방향은 한번밖에 못꺾는다
그래서 반복문으로 언제 방향을 틀껀지를 제어해주면 문제를 해결 할 수 있다.
숫자 야구 문제
#include <string> #include <vector> #include <iostream> using namespace std; int solution(vector<vector<int>> baseball) { int answer = 0; vector<pair<string, int>> num_list; for(int i = 100; i < 1000; i++){ string temp = to_string(i); int arr[10] = {0,0,0,0,0,0,0,0,0,0}; for(int j = 0; j < 3; j++){ if(temp[j] == '0') break; if(arr[temp[j] - '0'] == 0){ arr[temp[j] - '0'] = 1; }else{ break; } if(j == 2) num_list.push_back({temp, 1}); // 1 아직 후보, 0 탈락 } } for(int i = 0; i < baseball.size(); i++){ string cur = to_string(baseball[i][0]); int strike = baseball[i][1]; int ball = baseball[i][2]; //스트라이크 갯수를 먼저세고 어디서 스트라이크인지 확인한다. for(int index = 0; index < num_list.size(); index++){ string num = num_list[index].first; // 스트라이크 갯수 확인 int strCount = 0; int ballCount = 0; int arr[3] = {0,0,0}; for(int m = 0; m < 3; m++){ if(num[m] == cur[m]){ //스트라이크인 경우 갯수를 세고 다음으로 넘어간다(볼일 수는 없음) arr[m] = 1; // 1이면 스트라이크 된거 strCount++; continue; } if(m == 0 && (num[m] == cur[1] || num[m] == cur[2])){ ballCount++; continue; }else if(m == 1 && (num[m] == cur[0] || num[m] == cur[2])){ ballCount++; continue; }else if(m == 2 && (num[m] == cur[0] || num[m] == cur[1])){ ballCount++; continue; } } if(strCount != strike || ballCount != ball){ num_list[index].second = 0; continue; } } // 스트라이크 1 // if(strike == 0){ // // 숫자와 위치가 모두 맞는게 없음 // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second==0) // continue; // string temp = num_list[j].first; // if(temp[0] == cur[0] || temp[1] == cur[1] || temp[2] == cur[2]) // num_list[j].second = 0; // } // }else if(strike == 1){ // // 숫자와 위치가 맞는게 하나가 있다. // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second==0) // continue; // string temp = num_list[j].first; // if(temp[0] == cur[0] && temp[1] != cur[1] && temp[2] != cur[2]){ // continue; // } // if(temp[0] != cur[0] && temp[1] == cur[1] && temp[2] != cur[2]){ // continue; // } // if(temp[0] != cur[0] && temp[1] != cur[1] && temp[2] == cur[2]){ // continue; // } // num_list[j].second = 0; // } // }else if(strike == 2){ // // 두개는 맞고 하나가 틀렸다(숫자가 틀림) // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second==0) // continue; // string temp = num_list[j].first; // if(temp[0] == cur[0] && temp[1] == cur[1] && temp[2] != cur[2]){ // continue; // } // if(temp[0] == cur[0] && temp[1] != cur[1] && temp[2] == cur[2]){ // continue; // } // if(temp[0] != cur[0] && temp[1] == cur[1] && temp[2] == cur[2]){ // continue; // } // num_list[j].second = 0; // } // }else if(strike == 3){ // // 정답 // return 1; // } // if(ball == 1){ // // 맞는 숫자가 하나가 있고, 그위치말고 다른데 있다. // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second==0) // continue; // string temp = num_list[j].first; // // cout << temp << "," << cur << "\n"; // if(temp[0] != cur[0] && (temp[0] == cur[1] || temp[0] == cur[2])){ // cout << "1: "<<temp << "," << cur << "\n"; // continue; // } // if(temp[1] != cur[1] && (temp[1] == cur[0] || temp[1] == cur[2])){ // cout << "2: "<<temp << "," << cur << "\n"; // continue; // } // if(temp[2] != cur[2] && (temp[2] == cur[0] || temp[2] == cur[1])){ // cout << "3: "<<temp << "," << cur << "\n"; // continue; // } // num_list[j].second = 0; // } // }else if(ball == 2){ // // 맞는 숫자가 두개 있고, 다 다른데 있다. // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second==0) // continue; // string temp = num_list[j].first; // if(temp[2] != cur[0] && temp[2] != cur[1] && temp[2] != cur[2]){ // // 0, 1이 같을때 // if(temp[0] != cur[0] && (temp[0] == cur[1] || temp[0] == cur[2]) && temp[1] != cur[1] && (temp[1] == cur[0] || temp[1] == cur[2])) // continue; // } // if(temp[0] != cur[0] && temp[0] != cur[1] && temp[0] != cur[2]){ // // 1, 2이 같을때 // if(temp[1] != cur[1] && (temp[1] == cur[0] || temp[1] == cur[2]) && temp[2] != cur[2] && (temp[2] == cur[0] || temp[2] == cur[1])) // continue; // } // if(temp[1] != cur[0] && temp[1] != cur[1] && temp[1] != cur[2]){ // // 0, 2같을때 // if(temp[0] != cur[0] && (temp[0] == cur[1] || temp[0] == cur[2]) && temp[2] != cur[2] && (temp[2] == cur[0] || temp[2] == cur[1])) // continue; // } // num_list[j].second = 0; // } // }else if(ball == 3){ // // 맞는 숫자가 세개 있고, 다 다른 위치에 있다. // string temp1 = to_string(cur[0]) + to_string(cur[2]) + to_string(cur[1]); // string temp2 = to_string(cur[1]) + to_string(cur[0]) + to_string(cur[2]); // string temp3 = to_string(cur[1]) + to_string(cur[2]) + to_string(cur[0]); // string temp4 = to_string(cur[2]) + to_string(cur[0]) + to_string(cur[1]); // string temp5 = to_string(cur[2]) + to_string(cur[1]) + to_string(cur[0]); // for(int j = 0; j < num_list.size(); j++){ // if(num_list[j].second == 0) // continue; // if(num_list[j].first == cur){ // num_list[j].second = 0; // continue; // } // if(num_list[j].first == temp1 || num_list[j].first == temp2 || num_list[j].first == temp3 || num_list[j].first == temp4 || num_list[j].first == temp5 ) // continue; // num_list[j].second = 0; // } // } } for(int i = 0; i < num_list.size(); i++){ // cout << num_list[i].first << "\n"; if(num_list[i].second == 1){ cout << num_list[i].first << "\n"; answer++; } } return answer; }
이건 푸는데 정말 오래걸렸는데, 문제를 정말 잘읽자는 교훈을 주는 문제
- 문제 요약:
숫자는 모두 다르다 -> 세개를 고른다
게임을 직접 해본다
-풀이 방법:
1)포문을 통해서 가능한 숫자 후보군을 만들었다. 이것도 첨에 잘못 만들어서 111이런것도 포함시켜서 계속 정답 갯수가 틀렸다.
2)각각의 baseball 경우에 따라 각 숫자 후보군의 스트라이크와 볼 갯수를 매번 구했다.
이문제의 경우 숫자도 많아도 100~1000사이고, 후보가 안되는숫자도 엄청 많은데다가 baseball도 최대 100개뿐이라 포문으로 단순히 계산해도 된다.
각 숫자에 대해
baseball에 비교할 숫자를 cur 이라고 하고 num은 내가 만든 숫자 후보군 중 원소
cur 과 num의 각자리와 비교해서 같으면 같으면 스트라이크 카운트를 증가
각자리의 값이 다르면 볼인지 체크(0번째 자리 숫자를 비교 중이었으면 1번째 자리나 2번째 자리에 같은 값이 있는지 체크)
어려운 문제가 아니었는데, 문제를 제대로 이해를 못해서 오래걸렸다. 아래 주석은 문제를 잘못이해하면 얼마나 삽질을 하게 되는지 기록해둔것이다..
라면공장
#include <string> #include <vector> #include <iostream> using namespace std; int solution(int stock, vector<int> dates, vector<int> supplies, int k) { int answer = 0; // stock이랑 supplies최소 갯수 합으로 k이상을 만들 수 있을때 supplies갯수 int next = stock; // dates는 작거나 같은 애들중에 가장 수량 많은애로 고른당 int day = 0; vector<int> taken(dates.size(), 0); while(next < k){ int index = 0; int ms = 0; for(int i = 0; i < dates.size(); i++) { if(dates[i] <= next && taken[i] == 0){ if(ms < supplies[i]){ index = i; ms = supplies[i]; } } } next += ms; day++; taken[index] = 1; } answer = day; return answer; }
이 문제는 특이한것 같다. 첨 풀어보는 유형
공급을 받는 횟수를 최대로 줄여야한다.
stock만큼은 버틸수 있다.
stock이 4이면 dates가 4이거나 그거보다 작은애들로부터 물량을 받으면 되고(supplies), 그중에서도 supplies값이 가장 큰날부터 먼저 받는다.
매번 dates[0]부터 조회하기때문에, 이미 수량을 받은 경우를 체크하는 taken 벡터를 이용한다.
next라는 변수로 stock을 누적하는데, 누적값이 k보다 작을때까지 반복한다!
소감
레벨2문제들은 쉽지만, 반복문이나 조건문을 더 정확히 이해하고 사용하는 연습을 하기에 더 좋은 문제같다. 어려운 문제들은 문제 자체를 해결하는데 급급한데, 그것보다는 쉬운데 내가 부족한 부분을 콕콕찝어서 아는것처럼 헤매게 된다. 꾸준이 레벨2를 반복하고 기본기를 재정비한다음 다시 고난이도 문제를 풀어야겠다. 그래도 7주간동안 꾸준히 알고리즘 공부를 해온게 뿌듯하다. 실력이 아직은 어떨때는 는것 같다가도, 오늘처럼 별로 어려운 문제도 아닌데 삽질할때는 이게 실력이 늘까, 싶고 걱정도 되지만 꾸준히 하다보면 언젠가 깨우치는 날이 올것 같다.
'old > Algorithm' 카테고리의 다른 글
9주차 알고리즘 매주 세문제 풀기(튜플, 다음 큰 숫자, 땅따먹기, 포켓몬) (0) 2020.08.04 8주차 가장큰정사각형찾기/단체사진찍기/올바른괄호 (0) 2020.07.25 6주차 - 우선 순위 큐 사용 문제 (0) 2020.07.18 6주차 후기(레벨 2가 너무 어려워요) (0) 2020.07.17 5주차 - 카카오 가사검색 문제 (0) 2020.07.12