약수의 개수와 덧셈 문제 링크 

 

리뷰 

숫자 범위가 1000 이하다. n의 약수는 n을 1부터 n까지 나눴을 때, 나머지가 0인 수이다. 

1과 자기자신 n은 약수에 항상 포함된다. 

 

"맞았습니다"코드 

#include <string>
#include <vector>

using namespace std;
bool check(int n){
  int cnt = 0;
  for(int i =1; i <= n; i++) {
    if(n % i == 0) cnt++;
  }
  return (cnt % 2 == 0)? 1 : 0;
}
int solution(int left, int right) {
  int answer = 0;

  for(int i = left; i <= right; i++){
    if(check(i)) answer += i;
    else answer -= i;
  }
  return answer;
}
728x90

징검다리 문제 링크 

 

리뷰 

코딩테스트 고득점 키트의 '이분탐색'카테고리에 있는 문제다. 

바위 중에 n개를 제거했을 때, 바위 간 거리의 최소값중에서 최대가 되는 값이 답이 된다. 

 

도착 위치는 distance로 주어지고, 출발 위치는 항상 0이다. 

만약 바위가 1개인데 위치가 5 라면, 바위 간 거리는 0~ 5,  5 ~ distance 를 비교한다. 

둘 중에 거리차이가 최대인게 답이다.

 

도착 위치 distance 는 1이상 1억 이하다. 따라서 이분탐색으로 범위를 빠르게 좁혀줘야 한다. 

이분 탐색의 대상은 '거리의 최소값' 이다. 

바위 위치 배열을 오름차순 정렬 하고, 거리의 최소값이 mid를 만족하는지 모든 바위에 대해 검사한다. 

 

바위 n개를 제거하면서, 모든 바위간의 거리의 최소값이 mid임을 만족해야 한다.

바위 간의 거리차이가 mid 미만이라면, 조건을 만족하니까 제거한 바위 카운팅을 증가시킨다. 

 

만약, 제거한 바위가 n개를 초과한다면, 거리의 최소값 mid 크기를 줄여야한다. 

n개 이상을 제거 해야 거리의 최소값이 mid 임을 만족시킨다는 의미이기 때문이다. 

 

"맞았습니다" 코드 

#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int solution(int distance, vector<int> rocks, int n) {

  sort(rocks.begin(), rocks.end()); // 오름차순 정렬
  int rlen = rocks.size(), answer = 0;
  int left = 0, right = distance;

  // 거리의 최소값이 mid 이하인지 검사한다.
  while(left <= right){
    int mid = (left + right ) /2; // 거리의 최소값
    int prev_idx = 0; // 직전 바위의 위치
    int remove_cnt = 0; // 제거한 바위 개수

    for(int i = 0; i < rlen; i++){
      if(rocks[i] - prev_idx < mid) { // 거리 차이가 mid 이하라면 제거한다.
        remove_cnt++;
      }else{
        prev_idx = rocks[i];
      }
    }
    // 도착지점과 마지막바위 간의 거리차이가 mid 이하라면 제거
    if(distance - prev_idx < mid) remove_cnt++;
    if(remove_cnt <= n) {
      answer = max(mid, answer); // n개 이하로 제거했다면, 거리의 최소값을 증가시켜본다.
      left = mid + 1;
    } else{
      right = mid - 1; // 거리의 최소값을 더 줄여본다.
    }
  }
  return answer;
}

 

728x90

도둑질 문제 링크 

 

리뷰 

인접한 두 집을 털면 경보가 울린다. 따라서 한 개 건너서 털어야 한다. 

집이 동그랗게 이어져있으니까, 첫번째 집을 털면 마지막 집은 털 수 없다. 

마지막 집을 털면 첫번째 집은 털 수 없다. 이걸 구분해서 DP 배열을 만들어야한다. 

 

첫 번째 집을 턴다 (== 마지막 집 못 턴다)

 

마지막 집을 턴다 (== 첫번째 집 못 턴다)

 

"맞았습니다"코드

#include <vector>
#include <algorithm>
using namespace std;

int D1[1000001]; // 첫번째 집을 턴다
int D2[1000001]; // 첫번째 집 안털고, 마지막 집을 턴다.

int solution(vector<int> money) {
  int answer = 0;
  int msize = money.size();

  D1[0] = money[0]; // D1: 첫번째 집을 턴다.
  D1[1] = max(money[0], money[1]);

  D2[0] = 0;        // D2: 마지막 집을 턴다.
  D2[1] = money[1];

  for(int i = 2; i < msize-1 ; i++) { // 첫번째 집을 터니까 msize-2 까지 반복.
    D1[i] = max(D1[i-2] + money[i], D1[i-1]);
  }
  for(int i = 2; i < msize; i++) { // 마지막 집을 터니까 msize-1 까지 반복.
    D2[i] = max(D2[i-2] + money[i], D2[i-1]);
  }
  answer = max(D1[msize-2], D2[msize-1]);
  return answer;
}
728x90

 

수열 2559번 문제링크 

 

연속된 k개의 합을 구하되, 최대 합을 답으로 내는 문제다.

항상 k개여야 하니까, 시작 인덱스 0, 끝 인덱스 k-1 의 합으로 시작한다.

길이가 일정한 누적합이기 때문에, 시작 인덱스와 끝 인덱스만 바뀐다. 투포인터 문제다. 

 

k= 3 이라면,  아래 처럼 인덱스가 일정하게 증가한다. 

시작0 ~ 끝2,  시작1 ~ 끝3, 시작2 ~ 끝4

현재 시작인덱스의 값을 빼주고, 현재 끝인덱스 +1 의 값을 더해주면 된다. 

 

 

"맞았습니다"코드 링크 

#include <bits/stdc++.h>
using namespace std;

int n, k, start_idx, end_idx;
long long sum, sum_temp;

int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);

  cin >> n >> k;
  vector<int> v(n); 
  for(int i = 0; i < n; i++) cin >> v[i]; // 입력받기 끝 

  // 인덱스 0부터 k-1까지 k개의 합 
  for(int i = 0; i < k; i++) sum_temp += v[i];
  start_idx = 0, end_idx = k-1; 

  sum = sum_temp;
  
  while(end_idx < n){ 
    sum_temp -= v[start_idx++]; // 현재 인덱스 값 빼기, 인덱스 증가
    if(end_idx + 1 == n) break;
    sum_temp += v[++end_idx];   // 인덱스 증가시킨 후 그 인덱스 값 더하기
    sum = max(sum_temp, sum);
  }
  cout << sum;
  return 0;
}
728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 기타레슨 c++  (0) 2022.06.21
수들의 합2 백준 2003번 c++  (0) 2022.05.24
AC 백준 5430번 c++  (0) 2022.03.05
뱀과 사다리 게임 백준 16928번 c++  (0) 2022.03.02
조합 백준 2407번 c++  (0) 2022.03.02

 

문제링크

 

연속된 수들의 합을 구해야한다.

수열의 시작 인덱스 a와 마지막 인덱스 b 를 두고 합이 m이 나오면 개수를 세준다. 

인덱스 a와 b는 같을 수 있다. b는 수열 길이 n 직전까지 증가한다.

 

계속 다른 수열합을 확인해야 하니까 a와 b 인덱스는 계속 증가한다.

단, a가 b보다 큰 인덱스가 되면 안된다.  a <= b  여야 한다. 

 

누적 합 sum이 m보다 작다면, 수열의 마지막 인덱스 b를 증가시킨다. 

누적 합 sum이 m보다 크다면, 수열의 시작 인덱스 a를 증가시킨다. 

 

 

맞았습니다 코드 링크 

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll a, b, sum, n, m, answer;
int arr[10005];
int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);

  cin >> n >> m;
  for(int i = 0; i < n; i++ ) cin >> arr[i];

  sum = arr[a];
  while(b < n && a <= b){
    if(sum <= m){
      if(sum == m) answer++;
      sum += arr[++b];
    }else { // sum > m
      sum -= arr[a++];
      if(a > b){
        b = a;
        sum = arr[a];
      }
    }
  }
  cout << answer;
  return 0;
}
728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 기타레슨 c++  (0) 2022.06.21
수열 백준 2559번 c++  (0) 2022.05.24
AC 백준 5430번 c++  (0) 2022.03.05
뱀과 사다리 게임 백준 16928번 c++  (0) 2022.03.02
조합 백준 2407번 c++  (0) 2022.03.02

이진 변환 반복하기 문제링크

 

리뷰 

 

0제거 개수

문자열에서 0을 제거할 때 카운팅하고, 1이면 새로운 string에 이어붙였다.

 

이진수 변환 횟수

2로 나눈 나머지를 문자로 바꿔서 새로운 string에 이어붙였다. 

 

맞았습니다 코드 

#include <string>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> solution(string s) {
  vector<int> answer(2, 0);

  while(s != "1"){
    string temp = "";

    for(int i = 0; i < s.size(); i++){ 
      if (s[i] == '0') answer[1]++; // 제거한 0의 개수 세기
      else temp += "1";
    }
    int c = temp.size(); // temp의 길이 c
    string c_st = "";
    
    while(c > 0){ 
      c_st += to_string(c % 2);
      c /= 2;
    }
    answer[0]++; // 이진 변환 횟수 카운팅
    reverse(c_st.begin(), c_st.end()); // 이진수를 s에 대입
    s = c_st;
  }
  
  return answer;
}
728x90

숫자의 표현 문제링크 

 

리뷰 

입력이 15일 때, 15 하나 자체도 표현 방법으로 친다. 

그래서 answer 는 1로 초기화한다. 

 

15를 2로 나눴을때의 몫 부터 연속된 수를 더해본다. 

15를 2로 나눴을때의 몫은 7이다. 

 

7부터 더해보고,

6부터 더해보고, 

5부터 더해보고, 

.... 

1부터 더해보고. 

15/2 부터 1까지 누적 덧셈을 시도한다. 더하다가 n과 똑같아지면 카운팅한다. 

 

맞았습니다 코드 

#include <string>
#include <vector>
using namespace std;

int solution(int n) {
  int answer = 1;
  int start = n/2;

  for(int i = start; i > 0; i--){ // start 부터 1 까지.
    int sum = i, j = i+1; // 합을 저장할 sum, 더해줄 숫자 j
    while(sum <= n){
      sum += (j++);
      if(sum == n) {answer++; }
    }
  }
  return answer;
}

 

728x90

JadenCase 문자열 만들기 문제링크

 

리뷰 

문자열에는 숫자도 공백문자도 포함되어 있다.

문자열을 하나씩 순회해서 문자마다 알파벳이 맞는지 확인하는 isalpha() 함수를 썼다. 이건 불필요한 작업이었다. 

공백이든 숫자든 toupper() 와 tolower() 에 영향을 받지 않고 에러도 안낸다..

공백과 연속된 문자를 대문자로 바꾸고, 나머지는 전부 lower 처리 하면 된다. 

 

맞았습니다 코드1

#include <string>
#include <vector>
using namespace std;

string solution(string s) {

  string answer = "";
  string space_delimiter = " ";
  int pos = 1;

  while(pos != string::npos){
    pos = s.find(space_delimiter);
    string w = s.substr(0, pos);

    if (isalpha(w[0])) { w[0] = toupper(w[0]); };
    for(int i = 1; i < w.size(); i++){
      if (isalpha(w[i])) { w[i] = tolower(w[i]); };
    }
    answer += (w + " ");
    s.erase(0, pos + space_delimiter.length());
  }
  answer = answer.substr(0, answer.size()-1);
  return answer;
}

 

 

더 짧은 맞았습니다 코드2

#include <string>
#include <vector>
using namespace std;

string solution(string s) {
  string answer = "";

  answer += toupper(s[0]);
  for(int i = 1; i < s.size(); i++){
    if(s[i-1] == ' '){ // 공백 뒤에 대문자
      answer += toupper(s[i]);
    }else{
      answer += tolower(s[i]);
    }
  }

  return answer;
}
728x90

문제 링크 

리뷰 

1이 나타나는 곳에서 1이 끝날때 까지의 길이를 세서 정사각형인지 확인하는 방법을 썼다. 

근데 테스트 케이스 몇개가 안되서 다른 방법이 필요했다. 

 

맞았습니다 코드 

#include <bits/stdc++.h>
using namespace std;

int solution(vector<vector<int>> board)
{
  int answer = board[0][0];
  int h = board.size();
  int w = board[0].size();

  for(int i = 1; i < h; i++){
    for(int j = 1; j < w; j++){
      if(board[i][j] == 1){
        // 오른쪽, 아래, 대각선의 최소값을 구하고, 1을 더한다.
        board[i][j] = 1 + min({board[i-1][j-1], board[i][j-1], board[i-1][j]});
        answer = max(board[i][j], answer);
      }
    }
  }
  return answer * answer;
}

 

 

 

728x90

지도 자동 구축 문제 링크 

 

리뷰 

점 개수가 늘어나는 규칙보다는 전체 개수의 규칙을 셌다. 

0단계에서 한 변의 점 개수는 2개다. 

1단계에서 한 변의 점 개수는 3개다. 

2단계 에서는 5개, 3 단계에서는 9개가 된다. 

 

사각형의 전체 점 개수는 한 변의 점 개수의 제곱이다. 

2, 3, 5, 9  ==>  2의 0승 1승 2승 만큼 증가한다.  여기서 DP를 이용해 짰다. 

 

맞았습니다 코드 

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int n;
ll D[10];
int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);

  cin >> n;
  D[0] = 2, D[1] = 3;
  ll addnum = 1;
  for(int i =2; i <= n; i++){
    addnum *= 2;
    D[i] = D[i-1] + addnum;
  }
  cout << D[n] * D[n];
  return 0;
}

 

제출기록

728x90

+ Recent posts