1. 소수 찾기
어떤 숫자의 list(0, 1, 2, 3, ...)이 주어졌을 때
size가 1인 순열
size가 2인 순열
...
size가 list.size()인 순열
을 모두 구하고, 소수인지 판정하면 되었다.
2. 조이스틱
greedy라고 나와 있지만.. 이 문제가 진짜 greedy인지 나는 모르겠다. 그래서 brute-force로 풀었다.
어떤 문자열이 있으면, 그 문자열의 제일 앞에 있는 문자를 제일 뒤로 보낸다. 이렇게 만들어진 문자열(temp)의 index 0으로 이동해야 하는 거리를 구하고, 그 temp 문자열에서 왼쪽으로 쭉 갈 때, 오른쪽으로 쭉 갈 때 좌/우 이동의 최솟값을 구한다(A가 아닌 idx를 찾으면 된다). 이 두 값의 합이 기존 문자열에서 이동해야 하는 좌우 이동 거리이다.
모든 temp에 대해 위 연산을 수행한다면 brute-force하게 풀 수 있다.
2번 이상 왕복하는 경우는 1번 왕복하는 것보다 비효율적이므로 고려하지 않는다.(temp에서 일직선 이동만 고려하면 된다)
예를 들어
BABAAAAABAB 이런 경우를 보자
2 1 4 3 이게 최선일 것임. 답 11, (가로이동 7)
그러니까
모든 temp 문자열 1번씩 순회하면서(길이 20이니 시간 충분) 양쪽으로 방향만 보면 될 것.
ABAAAAABABB 기본 1 + min(10(오른족), 10)
BAAAAABABBA 기본 2 + min(5(왼쪽), 9)
AAAAABABBAB 기본 3 + min(10(오른쪽, 6)
...
이런 식으로 세 갈것임.
그러면 더이상 가지 않아도 되는 건 어떻게 아느냐...
temp 문자열에서 오른쪽으로 가는 경우, idx 0 기준으로 봤을 때 A가 아닌 문자열의 오른쪽 끝을 찾으면 되고
temp 문자열에서 왼쪽으로 가는 경우, idx 0 기준 왼쪽으로 가서 A가 아닌 문자열의 끝을 찾으면 될 것임.
int calDist(char input){ return min(input - 'A', 'Z' - input + 1); } int solution(string name) { if(name == "") return 0; int left, right, answer = 2000000000, length = name.length(); string temp; // string 제일 앞에 있는 걸 뒤로 1개씩 밀면서 min value 탐색 for(int i = 0; i<length; i++){ temp = name.substr(i, length - i) + name.substr(0, i); // temp : 초기 name으로부터 i개의 문자를 뒤로 민 문자열 left = right = 0; // left : temp에서 왼쪽으로 이동시켰을 때 마지막까지 이동시키면 되는 idx for(int idx = 1; idx < length; idx++){ if(temp[idx] != 'A'){ left = idx; break; } } left = length - left; // right : temp에서 오른쪽으로 이동시켰을 때 마지막까지 이동시키면 되는 idx for(int idx = length-1; idx > 0; idx--){ if(temp[idx] != 'A'){ right = idx; break; } } // min(i, length - i); // 초기 name으로부터 i개의 문자를 민 temp까지 최소 이동 횟수 answer = min(answer, min(i, length-i) + min(left, right)); } int differ = 0; for(int i = 0; i<length; i++){ differ += calDist(name[i]); } return answer + differ; }
3.다리를 지나는 트럭
이것도 그냥 간단하게 시간을 계속 1씩 더해가면서 조건에 따른 검사를 하는 방법이 있고, 시간을 때때로 skip해가는 방법이 있다. 나는 문제 제한조건에서 bridge_length가 1만, 입력이 1만이라 1만 * 1만 = 1억이니 안 될 것 같아서 후자의 방식을 택했다. (전자도 패스는 한다. 다만 후자가 훨씬 빠르다.)
알고리즘 간단하다. 먼저 시간이 1이 되는 시점에 첫 waiting queue에 있는 트럭을 넣고 시간 ++ 해준다.
이후 passing queue가 빌 때까지
- 만약 passing queue의 제일 앞에 있는 걸 뺄 수 있다면 빼고 현재 다리 위 트럭 무게 합을 계산한다.
- 이후 새로운 트럭을 올릴 수 있다면 올리고, time ++ 해주고 continue 한다.
- 만약 새로운 트럭을 올리지 못한다면 passing queue의 front()에 있는 트럭이 다음에 바로 빠져나가게 시간을 조정한다.
이 때 에러가 하나 있었는데. passing_queue가 empty인 상황에서도 front의 값을 읽어오는(메모리 에러) 오류가 있어서 디버깅한다고 시간을 많이 잡아먹었다.
#include <string> #include <vector> #include <stack> #include <queue> #include <iostream> using namespace std; typedef pair<int, int> pii; int solution(int bridge_length, int weight, vector<int> truck_weights) { int size = truck_weights.size(); queue<pii> passing_queue; queue<int> waiting_queue; int time = 1, cur_weight = truck_weights[0]; // 1초 딱 시작하자마자 들어가는 걸로. passing_queue.push({truck_weights[0], time}); time++; for(int i = 1; i<size; i++){ waiting_queue.push(truck_weights[i]); } // trucks[i].first : 트럭 weight, .second : truck이 다리에 진입한 시간. while(!passing_queue.empty()){ if(passing_queue.front().second + bridge_length <= time){ cur_weight -= passing_queue.front().first; passing_queue.pop(); } // 나가야 할 때 빼 줌. if(!waiting_queue.empty() && cur_weight + waiting_queue.front() <= weight){ passing_queue.push({waiting_queue.front(), time}); cur_weight += waiting_queue.front(); waiting_queue.pop(); time++; } // 더 올릴 수 있으면 올리고, time++ 해줌. else { if(!passing_queue.empty()){ time = passing_queue.front().second + bridge_length; } } // 더 올리지 못하는 경우는 시간을 skip해버림. // 이 때 에러가 하나 있었는데. passing_queue가 empty인 상황에서도 front의 값을 읽어오는(메모리 에러) 오류가 있었음. } return time; } // 아래 코드보단 조금 효율적으로 바뀜. // 무조건 시간을 1씩 더해가는 게 아니라 더 이상 올리지 못할때는 시간을 skip해버리기 때문임. /* int solution(int bridge_length, int weight, vector<int> truck_weights) { int clock = 0; // 시간초 int passing_sum = 0; // 다리를 건너는 트럭의 무게 합 queue<int> q; // 대기 트럭 int truck_num = truck_weights.size(); for(int i = 0; i<truck_num; i++){ q.push(truck_weights[i]); } queue<pair<int, int>> passing_q; // first는 진입한 clock(clock+bridge_length가 되면 나가야함), second는 그 차의 무게 while(!q.empty()){ if(!passing_q.empty() && clock == passing_q.front().first + bridge_length){ passing_sum -= passing_q.front().second; passing_q.pop(); } if(q.front() + passing_sum <= weight){ passing_sum += q.front(); passing_q.push({clock, q.front()}); q.pop(); } clock++; } clock += bridge_length; // q(대기 queue)가 빈 순간 마지막 차가 다리에 올라왔으므로... clock += bridge_length하는 게 답. return clock; }*/ // (다리를 건너는 트럭)에 있는 시간이 length만큼임. // 1초마다 다 계산가면 100,000,000 - 1억
4.2개 이하로 다른 비트
짝수인 경우 +1을 하면 되고, 홀수인 경우 뒤에서부터 연속되는 1 중 제일 앞의 것을 idx를 찾아 그 값만큼 더해주면 된다. 예전보다 비트 연산자를 사용할 수 있게 되는 것 같다(늘고 있는 듯!!!)
// 2개 이하로 다른 비트 vector<long long> solution(vector<long long> numbers) { int size = numbers.size(); vector<ll> answers(size); for(int i = 0; i<size; i++){ if(numbers[i] & 1){ ll idx = 1; while(numbers[i] & idx){ idx <<= 1; } idx >>= 1; answers[i] = numbers[i] + idx; } else{ answers[i] = numbers[i] + 1; } } return answers; } // 짝수 : +1하면 됨 // 홀수 : // 뒤에서부터 연속되는 1중 제일 앞의 것 idx을 찾아서 // idx-1와 idx를 바꾸면 된다
'PS > PS Log' 카테고리의 다른 글
22.04.05. 풀었던 문제들 (0) | 2022.06.22 |
---|---|
22.04.04 풀었던 문제들 (0) | 2022.06.22 |
22.04.01. 풀었던 문제들 (0) | 2022.06.22 |
22.03.31. 풀었던 문제들 (0) | 2022.06.22 |
22.03.30. 풀었던 문제들 (0) | 2022.06.22 |