알고리즘/알고리즘 관련 메모장

C++ - 2일차 백준 단계별로 풀기 5~7단계

잡담연구소 2020. 11. 8. 19:33

2일차라고 써놓고 한 3일 푼 듯 ^^ㅑㅇ

 

5단계 배열

 

c언어를 좀 되새겨보면 배열의 크기를 입력받으려면 미리 배열을 a[1000]으로 설정해놔야한다.

그럼 내가 입력을 5개만 받아도 995개의 기억장소의 낭비가 생긴다. 

이를 해결하는 것이 동적할당! 동적할당을 사용하면 배열의 크기를 프로그램 실행시 정해줄 수 있다.

calloc보다는 malloc이 손에 익어서 malloc만 쓸 거다.

 

#include<stdlib.h> // 동적할당을 사용하기 위해 stdlib.h라는 헤더파일이 필요하다.

int *a ; // 동적할당의 경우 일차원 배열의 이름 a 는 포인터변수이다. 

a = malloc(n*sizeof(int)); //int형 n개의 기억장소를 할당 

free(a) //메모리 해제 

 

이렇게 네 가지 정도가 바뀌는 듯 하다.

 

백준 10818 최소, 최대 문제 ( www.acmicpc.net/problem/10818 ) 에 대해서  

#include<stdio.h>

int main() {
    int n, a[1000000], i, min, max;
    scanf("%d", &n);

    for (i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    min = a[0];
    max = a[0];

    for (i = 1; i < n; i++) {
        if (a[i] < min) {
            min = a[i];
        }

        if (a[i] > max) {
            max = a[i];
        }
    }
    printf("%d %d", min, max);

}

이렇게도 풀 수 있지만 동적할당을 사용해서 풀면 

#include<stdio.h>
#include<stdlib.h>

int main() {
    int n, i, min, max;
    int *a;
    scanf("%d", &n);
    a = (int*)malloc(n*sizeof(int));

    for (i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    min = a[0];
    max = a[0];

    for (i = 1; i < n; i++) {
        if (a[i] < min) {
            min = a[i];
        }

        if (a[i] > max) {
            max = a[i];
        }
    }
    printf("%d %d", min, max);
    free(a);

}

 

백준 2562번 (acmicpc.net/problem/2562 )도 살짝 애먹었는데 순서는 1부터지만 배열은 0부터 시작이라는 걸 생각을 못하고 있었다. 

그래서 a[0] = 0 으로 대충 메꿔주고 a[1] 부터 a[9] 로 생각해줘서 해결함.

#include<stdio.h>

int main(){
    int a[10],i ;
    a[0] = 0;
    
    for(i=1;i<10;i++){
        scanf("%d" ,&a[i]);            
}
    
   int  ind = 0;
   int  max = a[0];
    
    for (i=1;i<10;i++){
        if (a[i] > max){
            max = a[i];
            ind = i;
        }
    }
    
    printf("%d\n%d" ,max, ind);
}

백준 2577번도 www.acmicpc.net/problem/2577  해결

#include<stdio.h>

int main() {
    int array[10] = {0};
    int a, b, c, i, result, number;
    scanf("%d", &a);
    scanf("%d", &b);
    scanf("%d", &c);

    result = a * b * c;

    while (1) {

        number = result % 10;
        array[number] += 1;
        result /= 10;

        if (result == 0)break;
    }

    for (i = 0; i < 10; i++) {
        printf("%d\n", array[i]);
    }
}

백준 3052번 (www.acmicpc.net/problem/3052) 42로 나누니까 나머지가 0~41일텐데 아무 생각없이 10이라고 생각하고 시간 날림 ㅠㅠ 

#include<stdio.h>

int main() {
    int array[42] = { 0 };
    int input, remain, i, count = 0;
    for (i = 0; i < 10; i++) {
        remain = 0;
        scanf("%d", &input);
        remain = input % 42;
        array[remain] += 1;
    }

    for (i = 0; i < 42; i++) {
        if (array[i] != 0) {
            count++;
        }

    }
    printf("%d", count);

}

백준 1546번 (www.acmicpc.net/problem/1546)

#include<stdio.h>
#include<stdlib.h>

int main() {
    int n, i;
    double * grade ,sum, max, temp;
    scanf("%d", &n);
    grade = (double*)malloc(n * sizeof(double));

    max = 0;
    for (i = 0; i < n; i++) {
        scanf("%lf", &grade[i]);
        if (grade[i] > max) {
            max = grade[i];
        }
    }

    sum = 0;

    for (i = 0; i < n; i++) {
        temp = grade[i];
        grade[i] = (temp /max) * 100;
        sum += grade[i];
    }

    printf("%lf", sum / n);


}

백준 8958번 (www.acmicpc.net/problem/8958 ) 날 화나게한다. 

그래서 string 공부하고 옴 히히 

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

int main() {
	int n;
	cin >> n;

	for (int i = 0; i < 5; i++) {
		string test;
		cin >> test;
		int cnt = 0, sum = 0;
		for (int j=0; j < test.size(); j++) {
			if (test[j] == 'O') {
				cnt++;
				sum += cnt;
			}
			else cnt = 0;
		}
		cout << sum<<endl;
	}
}

백준 4344번 (www.acmicpc.net/problem/4344

%를 출력하려면 %를 두번 %% 이렇게 쳐줘야한다.

#include<stdio.h>
#include<stdlib.h>

int main() {
    int n, casenum, i, j, * score, sum, count;
    double average, ratio;
    scanf_s("%d", &casenum);

    for (i = 0; i < casenum; i++) {
        scanf_s("%d", &n);
        score = (int*)malloc(n * sizeof(int));

        sum = 0;
        count = 0;
        ratio = 0;

        for (j = 0; j < n; j++) {
            scanf_s("%d", &score[j]);
            sum += score[j];
        }

        average = sum / n;

        for (j = 0; j < n; j++) {
            if (score[j] > average) count++;
        }

        ratio = count / (double)n * 100;
        printf("%.3f%%\n", ratio);

    }
}

 

6단계 함수

백준 15596번 (www.acmicpc.net/problem/15596 )좀 매우 당황스럽당.

저렇게 배열을 입력받으면 배열의 크기 n은 어떡하지 싶었는데 그냥 배열.size() or 배열.length()

이렇게 간단하게 풀 수 있다. 

#include <vector>
long long sum(std::vector<int> &a) {
	long long ans = 0;
    int i;
    for (i=0;i<a.size();i++) ans+=a[i];
	return ans;
}

modoocode.com/223 정독하면 vecteor와 iteration의 개념에 대해 공부할 수 있다. 난 아이패드에 함 ㅎㅎ

그냥 길이가 매번 바뀌는 배열정도라고 생각하면 되는 vector 녀석과 python에서 햇던 iteration개념을 써서 문제를 풀 수도 있다.

#include <vector>
long long sum(std::vector<int>& a) {
	long long ans = 0;
	for (std::vector<int>::iterator itr = a.begin(); itr != a.end(); ++itr) ans += *itr;
	return ans;
}

 

 

백준 4673번 (www.acmicpc.net/problem/4673)

호오,,, 벌써 벽을 느꼈다. 문제 이해는 가는데 어떻게 풀어야 할 지, 아니 문제 이해도 잘 안되는 거 같다. 

역시 알아보니 넥슨 입사문제여따구^_^ 

생성자를 계속 만들어 낼 수 있는 거 아닌가 

16 -> 16+1+6=23 -> 23 + 2 + 3 -> 28 이런식으로 계속 만들어 낼 수 있는 거 아닌가 고민했는데 

어차피 23에서도 같은 생성자를 만들어 낼 거니까 한 번 씩만 만들어내도 충분한 거 같다. 

#include<iostream>
#include<stdio.h>
#define N 10001
using namespace std;

int main() {
	int generate(int);

	bool number[N] = { false };  // 10001 배열을 0으로 초기화

	for (int i = 1; i < N; i++) {
		int res = generate(i);
		if (res < N) number[res] = true;
	}

	for (int j = 1; j < N; j++) {
		if (!number[j]) cout << j << endl;
	}
}


int generate(int n) {
	int sum = n;

	while (n!=0) {
		sum += n % 10;
		n /= 10;
	}
	return sum;
}

 

 

백준 1065번 (www.acmicpc.net/problem/1065)

#include<stdio.h>

int sequence(int);

int main() {
	int n, i, count;
	scanf("%d", &n);

	if (n < 100) printf("%d", n);

	else if (99 < n < 1000) {
		count = 99;
        
		for (i = 100; i <= n; i++) {
			count += sequence(i);
		}
        
		printf("%d", count);
	}

	else {
		count = 99;
		for (i = 100; i <= 1000; i++) {
			count += sequence(i);
		}
		printf("%d", count);
	}
}


int sequence(int n) {

	int n1, n10, n100;
	
	n100 = n / 100;
	n %= 100;
	n10 = n / 10;
	n1 = n % 10;
	
	if (n100 - n10 == n10 - n1) return 1;
	else return 0;
}

두자리 이하의 숫자라면 자기자신이 곧 한수의 개수가 된다. 

세자리부터는 무조건 99 이상인데 잘 생각을 해보면 99에다가 

100부터 자기자신까지의 한수의 개수를 더해주면된다. 

그리고 1000은 999일때와 동일

 

백준에 나온 예제를 하나 애기해보면 210같은 경우

1~99까지 99개 + 111,123,135,147,159,210 (100부터 자기자신까지의 한수)이렇게 6개 총 105개가 나온다 

 

근데 visual에서 코드를 돌려봤을때는 백준에 나온 예제 모두 맞는데 틀렸단다 ㅠㅠ 

질문을 올려놓은 상태이니 답변이 달리면 수정하도록 ㅠㅠㅠ

 

+ 추가 ) 예예 답변이 달렸는데 문제점을 찾아냈습니다. 다른 문제 제출칸에다가 집어넣고있었음 ^_^... 바보같은 녀석 

 

 

7단계 문자열

백준 11654번(www.acmicpc.net/problem/11654)

기본 C에서 문자를 정수로 출력하면 아스키값이 나온다.

자꾸 이렇게 풀면 c랑 다른 게 뭔가 싶어서 현타와서 다시 iostream을 이용한다,,,

#include<iostream>
using namespace std;

int main() {
	char input;
    cin >> input;
    cout << (int)input;
}

백준 11720번 (www.acmicpc.net/problem/11720)

공백이 있으면 getchar등으로 받으면 되는데 이 문제는 공백이 없어서 그냥 cin으로 받아야지~ 했다가 

다시 생각해보니까 그걸 묻는 게 아니라 각 자리수를 자르는 거니까 문자열로 받아야되는구나! 번득임

number라는 문자열로 입력받아 하나하나 잘라준다. 근데 숫자1이 문자열이 아니라 아스키코드 48로 컴퓨터가 받아들인다. 그래서 다시 1로 바꿔주기 위해 '0' 이라는 문자의 값 (48) 만큼 빼주자. 

#include<iostream>
using namespace std;

int main(){
	int n , i , sum=0;
	cin >> n;

	char number[101];
	cin >> number;

	for (i = 0; i < n; i++) {
		sum += int(number[i]-'0');
	}

	cout << sum;
}

백준10809번 (www.acmicpc.net/problem/10809)

으아,,,초기화때문에 엄청 애먹었다. 덕분에 새로운 사실을 알게 되었다. 

맨날 배열= {0} 으로 초기화했어서 아무 생각 없이 {-1}로 초기화했는데 자꾸 안돼서 엄청 고민했는데 

배열 = {-1} 이 방법은 인덱스0만 -1이고 나머지는다 0이다. 헐 
 fill_n(배열, 인덱스, 초기화하고자하는숫자) 를 이용해서 모든 배열값을 다 -1로 바꿨더니 된다.

#include<iostream>
using namespace std;

int main(){
	int  alphabet[26];
	int num, i = 0;
	fill_n(alphabet, 26, -1);


	char string[100];
	cin >> string;

	while (string[i] != NULL ) {
		num = 0;
		num = int(string[i] - 'a');
		cout<<num<<endl;
		if (alphabet[num] == -1) alphabet[num] = i;
		i++;	
	}

	for (i = 0; i < 26; i++) {
		cout << alphabet[i]<<" ";
	}
}

백준 2675번 (www.acmicpc.net/problem/2675)

위에서 푼 거처럼 미리 문자열의 크기를 정해놓고 공백이 나오기 전까지 while문을 쓰는 게 불편해서 

string 클래스를 사용하자. 문자열의 크기를 지정해놓지 않고 정의한 후  ,  배열.length()를 쓰니 더 편한 거 같다.

#include<iostream>
using namespace std;

int main(){
	
	int n , i , j ,k ,repeat , sum ;
	string s;

	cin >> n; //testcase개수 입력받기
	
	for (i = 0; i < n; i++) {
		sum = 0;
		cin >> repeat >> s; //반복횟수 및 문자열 입력받기

		for (j = 0; j < s.length(); j++) {
			for (k = 0; k < repeat; k++) {
				cout << s[j];
			}
		}

		cout << endl;

	
	}

}

백준 1157번(www.acmicpc.net/problem/1157)

#include<iostream>
using namespace std;

int main(){

	int idx , alphabet[26] = {0};
	string word;
	cin >> word;

	for (int i = 0; i < word.size(); i++) {
		if (int(word[i] >= 97)) {
			idx = int(word[i]) - 32 - 65;
			alphabet[idx] ++;
		}
		else {
			idx = int(word[i] - 65);
			alphabet[idx] ++;
		}
	}
	// 최댓값 찾기 
	int max = 0 , ind = 0 , cnt = 0;

	for (int i=0; i < 26; i++) {
		if (alphabet[i] > max) {
			max = alphabet[i];
			ind = i;
		}
	}


	//max값 같은 거 있는 지 확인하기
	for (int i = 0; i < 26; i++) {
		if (i != ind and alphabet[i] == max) {
			cout << "?";
			cnt++;
			break;
		}	 
	}

	if(cnt==0) cout << char(ind+ 65) << endl;
}

 

백준 1152번 (www.acmicpc.net/problem/1152)

드디어 공백이 있는 문자열을 받아야하는 상황이 생겼다! 직전학기 C할떄는 gets를 썼던 거 같은데 기억이 잘 안난다.

getline랑 씹어먹는 c++ pdf 270쪽 꼴랑 보고 문제를 4시간 동안 고민했는데 안 풀린다 진짜 현타 제대로 옴 ....🤦‍♀️

모래성 인생 오혜린,,,,, string 클래스 사용법 먼저 알아야겠다고 4시간만에 생각함^_^

jhnyang.tistory.com/115?category=850633 여기 진짜 정리 잘해놓으심 👍💖 

 

문자열은 배열로 받는 데, 생각해보면 입력받아야할 문자열의 크기를 아는 경우는 흔치 않다. 

 c언어에서는 char sentence[100] 이런식으로 했다면, c++에서는 string 클래스를 사용하면 엄청 편리하다 .

 

10번 시도해서 드디어 성공함 ^_^..... 나온 예제는 다 맞는데 자꾸 틀렸습니다가 떠서 엄청 스트레스받다가 

질문검색을 통해서 반례를 찾았는데 아무것도 없이 공백하나만 주어질 때가 반례였다 .

맨 마지막에 무조건 cnt+1 이었는데 공백하나만 주어지면 +1을 하면 안되기때문에 

empty 면 cnt 아니면 cnt+1 로 조건문을 줘서 해결했다 흐흐흑

 

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

int main(){

	string sentence;
	getline(cin,sentence);


	if (int(sentence.front()) == 32) {
		sentence.erase(0,1);
	}

	if (int(sentence[sentence.size() -1]) == 32) sentence.erase(sentence.size() - 1 ,1);

	int cnt=0;

	for (int i = 0; i < int(sentence.size()); i++) {
		if (int(sentence[i]) == 32) cnt++;
	}

	if (sentence.empty() == 1) cout << cnt ;
	else  cout << cnt+1;
}

드디어 탈출이다 이녀석아,,,,! 다신 보지 말자 휴

 

백준2908번 (www.acmicpc.net/problem/2908)

strcmp는 -1,0,1 세 개 밖에 없는 줄 알았는데 아니었다. 앞으로는 음수 , 0 , 양수 이렇게 생각하도록@

#include<iostream>
#include<cstring>

using namespace std;

int main() {
	char a[4], b[4], new_a[4], new_b[4];
	cin >> a >> b;

	for (int i = 0; i < 3; i++) {
		new_a[i] = a[2 - i];
		new_b[i] = b[2 - i];
	}
	new_a[3] = '\0';
	new_b[3] = '\0';

	if (strcmp(new_a, new_b) < 0) cout << new_a;
	else cout << new_b;

}

 

백준 5622번 (www.acmicpc.net/problem/5622)

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

int alphabet2number(char);
int main() {
	string alphabet;
	cin >> alphabet;
	int sum = 0;
	for (int i = 0; i < alphabet.size(); i++) {
		sum += alphabet2number(alphabet[i])+1;
	}
	cout << sum;
}

int alphabet2number(char a) {
	int n = int(a);
	for (int i = 0; i < 5; i++) {
		if (65 + i * 3 <= n and n <= 67 + i * 3) return i + 2;
	}
	if (80 <= n and n <= 83) return 7;
	if (84 <= n and n<= 86) return 8;
	if (87 <= n and n<= 90) return 9;
}

백준 2941번(www.acmicpc.net/problem/2941)

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

int main() {
	string croa;
	cin >> croa;
	
	int sum = 0;
	int i = 0;
	int cnt = 0;

	while (1) {
		if (i >= croa.size()) break;
		
		if (croa[i] == 'c') {
			if (croa[i + 1] == '=' || croa[i + 1] == '-') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}
		else if (croa[i] == 'd') {
			if (croa[i + 1] == 'z' and croa[i + 2] == '=') {
				cnt++;
				i += 3;
			}
			else if (croa[i + 1] == '-') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}

		else if (croa[i] == 'l') {
			if (croa[i + 1] == 'j') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}

		else if (croa[i] == 'n') {
			if (croa[i + 1] == 'j') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}

		else if (croa[i] == 's') {
			if (croa[i + 1] == '=') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}

		else if (croa[i] == 'z') {
			if (croa[i + 1] == '=') {
				cnt++;
				i += 2;
			}
			else {
				cnt++;
				i++;
			}
		}

		else {
			cnt++;
			i++;
		}
	}
	cout << cnt;
}

 

멋진 방법 없을까 엄청 몇시간 동안 고민했는데 그런 건 없었다 ^_^ ...

여러가지로 시도해봤는데 가장 기본적인 노가다가 젤 잘 먹혀서 슬퍼ㅜ

 

백준1316번 (www.acmicpc.net/problem/1316)

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

int main() {
	int n;
	cin >> n;
	int sum = 0;

	for (int i = 0; i < n; i++) {
		string word;
		cin >> word;
		int cnt = 0, temp;

		for (int j = 0; j < word.size(); j++) {
			char alphabet = word[j];
			if (word[j + 1] != alphabet) {
				if (word.find(alphabet, j + 1) != -1)	cnt = 1;
			}
			else
			{
				for (int k = j; k < word.size(); k++) {
					if (word[k] != alphabet) {
						temp = k;
						if (word.find(alphabet, temp + 1) != -1)	cnt = 1;
					}
				}
			}

		}
		if (cnt == 0) sum++;
	}
	cout << sum;
}

 

 

 

이것도 좀 고민을 많이했다. 반복되는 숫자가 몇개인지 모르는 데 어떡하징 ㅠㅠㅠㅠㅠ

일단 word라는 스트링에 단어를 각각 입력받는다. 그리고 단어를 이루는 각각의 알파벳에 대해서 

1. j번째 나온 알파벳과 j+1번째 나온 알파벳이 다르다면

반복이 없다는 상황이다. 그렇다면 이 이후로 j번째에서 나온 알파벳이 또 나오면 안된다.

find함수를 사용해서 j 이후에 같은 알파벡이 오는지 확인한다. find(j번째 알파벳 , 탐색을 시작할 인덱스 즉 j 이후) 

같은 알파벳이 존재한다면 cnt값을 1로 바꿔준다. 

 

2. j번째 알파벳과 j+1번째 나온 알파벳이 같다면

반복한다는 상황이다. 하지만 언제까지 반복을 하는지 모른다. for문을 통해서 같은 알파벳이 더 이상 나오지 않는 인덱스를 찾아준다. 그 인덱스를 temp로 설정하고 temp 이후에 j번째 알파벳이 또 나오는지 find함수를 통해서 찾는다. 1번 상황과 비슷해짐 

 

예를 들어 설명하면 aaabba 이렇게 나오면

인덱스0에 a가 나오고 그 다음 인덱스1도 a니까 반복되는 2번 상황이다.  for문을 통해서 인덱스 1 이후에 a가 안나오는 인덱스를 찾는다. 그럼 처음으로 a가 아닌 인덱스는 3이므로 temp = 3이 된다. 

find (a,3) 즉, 3번째 인덱스부터 그 이후로 a를 찾는다. 만약 찾아지면 그룹단어가 아니니 cnt=1!

 

최종적으로 cnt가 1이면 그룹함수가 아니므로 cnt가 0 즉, 그룹함수일떼만 sum을 더해주자.

 

이렇게 해서 7단계까지 끝^~^ 

사실 자료구조를 공부해가야되는데ㅠㅠㅠㅠ 이것만 하고있다.