hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

PS/PS Log

23.08.01. 풀었던 문제들 복기

Leetcode 77. Combinations, 8분

 예전에 DFS로 순열/조합/중복순열/중복조합 코드를 썼었다. 코드야 그대로 쓰면 된다.

 예전에 짰던 게 제일 깔끔하게 짜였던 걸로 기억했는데, 이번에 안 보고 짠 것도 비슷하게 짜진다. 다행이군.

// Runtime 10 ms Beats 93.32%
// Memory 9.9 MB Beats 56.99%

class Solution {
public:
    vector<int> nums;
    vector<vector<int>> answer;
    void combination(int cur_d, int max_d, int prev_idx, vector<int>& result){
        if(cur_d == max_d){
            answer.push_back(result);
            return;
        }

        for(int i = prev_idx + 1; i<nums.size(); i++){
            result[cur_d] = nums[i];
            combination(cur_d+1, max_d, i, result);
        }
    }
    vector<vector<int>> combine(int n, int k) {
        for(int i = 1; i<=n; i++) nums.push_back(i);
        vector<int> result(k);

        combination(0, k, -1, result);

        return answer;
    }
};

 

 

 

BOJ 18310. 안테나, 21분

 처음에는 binary search로 푸는 문제인 줄 알았는데, 이 문제의 경우 parametric search의 형태가 아니다. 왜냐하면, binary search를 사용하기 위한 판정 함수가 O, X로 나타나지 않기 때문이다. 기준을 잡으면 O, X는 되는데,,, 기준을 뭘로 잡을지도 문제다. 양 옆을 계속 봐야 하니까. 이건 아닌 것 같지 않나?

 그래서 고민하다가... 정렬 후 가운데 위치면 결과가 최솟값일거라 생각해 그렇게 접근했고, 맞았다.

 중복을 지우면 안 되는 이유는 [1, 10, 10]을 보면 된다.

////////////////////// write your code below

// N = 20만, 범위는 10만
// BF로는 절대 못풀고, 아마 binary search인 듯.
// BS도 아닌 것 같기도 하고... OX로 표현할 수 있는 게 아님. 기준이 잡혀야 함.

int N;
vector<int> houses;	

void solve(){
	cin>>N;
	houses.resize(N);
	for(int i = 0; i<N; i++){
		cin>>houses[i];
	}	

	// sort
	sort(houses.begin(), houses.end(), less<int>());
	
	// get mid
	int mid = (N-1)/2;
	cout<<houses[mid];

	return;
}

 

시간복잡도

 O(nlogn)

 

 

 

BOJ 23742. Player-based Team Distribution, 27분

 그다지 어려운 문제는 아니었는데... 수식 실수로 오래 걸렸다.

 일단 첫 접근은

  • +인 애들은 다 한 팀으로 묶고
  • -인 애들은 다 따로따로 쓰면 되지 않을까?

였는데, [+ 팀에 아주 작은 - 하나를 더하면 결과값이 더 커지지 않나]? 에서 완벽한 솔루션을 얻었다. 이 때, 더하는 애들은 작은 순서부터 넣는게 더 많이 넣을 수 있기 때문에 절댓값이 작은 애들부터 넣으면 된다.

  1. arr에서 +인 애들은 sum에 전부 다 더하고, 개수를 cnt에 넣는다.
  2. 나머지 애들은 negs에 넣고 내림차순 정렬한다.
  3. 이후 negs의 모든 element, neg에 대해
    1. sum * cnt + neg <= (sum + neg) * (cnt + 1)이 true면 그 neg는 + 그룹에 넣어도 된다. 아닌 경우 혼자인 팀으로 만들면 됨.
    2. 이 때, 좌항은 +는 그룹으로, neg는 개인으로 셌을 때이고, 우항은 +그룹에 neg를 넣었을 때 점수 총 합이다.

 이렇게 잘 만들었는데, 실수는

 sum * cnt + neg로 해야 하는데 sum * cnt - neg로 한 것

 그리고 sum * cnt과 neg를 합친 값과 (sum + neg) * (cnt + 1)을 비교했어야 했는데 sum * cnt와만 비교한 것. 2가지 이다.

int N;
vector<int> arr;

void solve(){
	cin>>N;
	arr.resize(N);
	for(int i = 0; i<N; i++) cin>>arr[i];

	ll sum = 0;
	int cnt = 0;
	vector<int> negs;
	for(int i : arr){
		if(i >= 0){
			sum += i;
			cnt++;
		}
		else negs.push_back(i);
	}
	sort(negs.begin(), negs.end(), greater<int>());

	ll negsum = 0;
	for(int neg : negs){
		if(sum * cnt + neg <= (sum + neg) * (cnt + 1)){
			sum += neg;
			cnt++;
		}
		else negsum += neg;
	}

	cout<<sum * cnt + negsum;
}

 

시간복잡도

 전부 다 O(n)의 for문만 돌고, 정렬에 O(nlogn)이 걸리니까 O(nlogn)

 

공간복잡도

 arr, negs 배열을 사용하므로 O(n)

 

후기

 실수가 뼈아프다. 아니었더라면...

 

 

 

BOJ 10502 덧셈, 62분

 처음에는 binary search로 접근했다... ㅋㅋㅋㅋ 부끄럽다.

 그렇게 생각한 이유가, [시작점]과 [끝점]을 알아야 한다고 생각했기 때문이다. 그러나, 위에서 언급했던 것과는 다르게 이 경우 O, X를 판별할 수는 있다. 그러나 그것을 기점으로 시작점을 당겨야 하는지, 끝점을 밀어야 하는지 알 수가 없다.

 때문에 다른 접근이 필요하다.

 

 sumToI라는 배열 하나를 두고, sumToI[i]는 1부터 i+1까지 합을 넣어두자.

 N이 주어졌을 때, 모든 sumToI를 순회하면서 N - sum이 i+1로 나눠 떨어지는지를 보자. 만약 나눠 떨어진다면, 

  • 원래 1 + 2 + 3 + 4 + ...였던 것에
  • 나눠 떨어진 몫을 더하면 된다. 예를 들어 6이라면 7 + 8 + 9 + 10 + ...가 된다. 

 이렇게 풀 경우, sumToI의 i는 더한 숫자의 개수를 의미하기 때문에 문제가 제시하는 가장 짧은 표현도 만족한다.

vector<ll> sumToI; // sumToI[i] : 1부터 i+1까지 sum

void init(){
	int i = 1;
	ll sum = 0;
	while(1){
		sum = (i+1) * i / 2;
		i++;
		if(sum > 1e9) break;
		sumToI.push_back(sum);
	}
}

void solve(){
	int N; cin>>N;

	for(int i = 0; i<sumToI.size(); i++){
		ll sum = sumToI[i];
		if(N < sum) break;
		if((N - sum) % (i+1) == 0 && i != 0){
			ll gap = (N - sum) / (i+1);
			cout<<N<<" = ";
			for(int n = 1; n<i+1; n++){
				cout<<n+gap<<" + ";
			}
			cout<<i+1+gap<<'\n';
			return;
		}
	}
	cout<<"IMPOSSIBLE\n";
}

 

시간복잡도

 sumToI vector의 size는 약 5만 정도이다. t가 얼마나 주어질지 모르긴 한데.. 한 번에 O(5만)으로 풀 수 있다. 대충 t=2000까지 커버할 수 있다.

 

공간복잡도

 O(5만)의 sumToI를 사용하므로 O(5만)

 

후기

 코테용 공부니까.. 일단 brute-force로 먼저 접근을 해 보자.

 

 

 

2485. 가로수, 7분

 문제를 읽고, [간격을 같게 하기 위한 최소 개수]를 만들기 때문에.. 간격들의 최대공약수를 사용하면 된다. GCD는 포스팅 링크에 정리해 두었다.

// GCD같다. 어떻게 하더라?

ll getGCD(ll a, ll b){
	ll r;
	while(b != 0){
		r = a % b;
		a = b;
		b = r;
	}
	return a;
}

void solve(){
	int N; cin>>N;
	vector<ll> positions(N), gaps(N-1);
	for(int i = 0; i<N; i++) cin>>positions[i];
	for(int i = 1; i<N; i++) gaps[i-1] = positions[i] - positions[i-1];

	ll GCD = getGCD(gaps[0], gaps[1]);
	for(int i = 2; i<N-1; i++){
		GCD = getGCD(GCD, gaps[i]);
	}

	ll answer = 0;
	for(ll gap : gaps){
		answer += gap / GCD - 1;
	}
	cout<<answer;
}

 

시간복잡도

 GCD의 시간복잡도는 O(log(min(a, b))). 입력 정수는 10억이므로 min(a, b)를 10억으로 잡아도 log(10억)은 얼마 안 된다.

 

공간복잡도

 입력을 저장하기 위한 용도로 N size vector 2개를 쓰므로 O(N)

 

 

 

 

 

 

 

 

저작자표시 (새창열림)

'PS > PS Log' 카테고리의 다른 글

23.08.04. 풀었던 문제들 복기  (0) 2023.08.05
23.08.02. 풀었던 문제들 복기  (0) 2023.08.02
23.07.31. 풀었던 문제들 복기  (0) 2023.08.01
23.07.29. 풀었던 문제들 복기  (0) 2023.07.29
23.07.27. 풀었던 문제들 복기  (0) 2023.07.27
    hyelie
    hyelie

    티스토리툴바