250831
3문제
- 기사단원의 무기 ok
- 2016년
- 과일장수
기사단원의 무기
class Solution {
public int solution(int number, int limit, int power) {
// 번호의 약수 개수에 해당하는 공격력
// 단, 제한 수치 limit 넘어가면 power 구매
// limit = 공격력일 때는 limit 구매 가능
// 공격력 1당 철 1kg
// 모든 무기 만들기 위해 필요한 철의 무게 리턴
int answer = 0;
for (int i = 1; i <= number; i++) {
int paladinNum = i; // 기사 번호
int attackCnt = divisorCnt(i);
if (attackCnt > limit) {
answer += power;
} else {
answer += attackCnt;
}
}
return answer;
}
public int divisorCnt(int n) { // pladinNum의 공격력 약수 계산하는 메서드
int attack = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (i % j == 0) {
attack++;
}
}
}
return attack;
}
}
틀린이유 - 이중포문
divisorCnt 메서드에서 이중포문 씀.
main에서 for문 쓰고 있으니까 divisorCnt는 하나의 숫자 n에 대해서 약수 몇 개 인지 구하기만 하면 됨
수정한 코드
class Solution {
public int solution(int number, int limit, int power) {
// 번호의 약수 개수에 해당하는 공격력
// 단, 제한 수치 limit 넘어가면 power 구매
// limit = 공격력일 때는 limit 구매 가능
// 공격력 1당 철 1kg
// 모든 무기 만들기 위해 필요한 철의 무게 리턴
int answer = 0;
for (int i = 1; i <= number; i++) {
int paladinNum = i; // 기사 번호
int attackCnt = divisorCnt(i);
if (attackCnt > limit) {
answer += power;
} else {
answer += attackCnt;
}
}
return answer;
}
public int divisorCnt(int n) { // pladinNum의 공격력 약수 계산하는 메서드
int attack = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
attack++;
}
}
return attack;
}
}
틀린 이유 - 시간초과
- 약수구할때 √n까지만 확인하면 된다 약수는\느 항상 짝을 이루기 때문이다
- 작은 쪽 약수만 찾으면 큰 쪽은 자동으로 알 수 있다. 그래서 √n까지만 돌리면 모든 약수를 찾을 수 있다.
- i * i ≤ n
- if (i != n / i) attack++;
1. 내가 푼거 (O(n))
public int divisorCnt(int n) {
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) cnt++;
}
return cnt;
}
모든 수를 다 나눠보는 방식
2. 효율적인 방법 (O(√n))
public int divisorCnt(int n) {
int cnt = 0;
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
cnt++; // 작은 약수
if (i != n / i) cnt++; // 짝꿍 약수 (제곱수 중복 방지)
}
}
return cnt;
}
예를 들어 n=12라면
- i=1 → (1,12) → +2
- i=2 → (2,6) → +2
- i=3 → (3,4) → +2
- i=4부터는 i*i > n이므로 종료
- 최종 cnt = 6 (약수는 1,2,3,4,6,12)
수정한 코드
class Solution {
public int solution(int number, int limit, int power) {
// 번호의 약수 개수에 해당하는 공격력
// 단, 제한 수치 limit 넘어가면 power 구매
// limit = 공격력일 때는 limit 구매 가능
// 공격력 1당 철 1kg
// 모든 무기 만들기 위해 필요한 철의 무게 리턴
int answer = 0;
for (int i = 1; i <= number; i++) {
int paladinNum = i; // 기사 번호
int attackCnt = divisorCnt(i);
if (attackCnt > limit) {
answer += power;
} else {
answer += attackCnt;
}
}
return answer;
}
public int divisorCnt(int n) { // pladinNum의 공격력 약수 계산하는 메서드
int attack = 0;
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
attack++;
if (i != n / i) attack++;
}
}
return attack;
}
}
제곱수일 때 약수가 중복돼서 두 번 세지 않으려고 아래 코드 씀
if (i != n / i) attack++;
반례
예를 들어 n = 36
일 때 i = 6
n % 6 == 0
이니까6
은 약수 →attack++
- 그런데 짝꿍 약수는
n / i = 36 / 6 = 6
→ 자기 자신 - 즉, 이미
attack++
했는데 또attack++
하면6
을 두 번 세는 꼴
그래서 if (i != n / i)
를 붙여서 짝꿍이 자기 자신이 아닐 때만카운트하도록 추가하는 조건이다
과일장수
class Solution {
public int solution(int k, int m, int[] score) {
// 사고ㅏ몇 박스 ? score.length / m;
// 각 사과 점수 계산
int len = score.length; // 사과박스
int box = len / m; // 점수 길이
int answer = 0; // 최대이익
// 사과점수 내림차순
// int[] → Integerp[]로
Integer[] arr = Arrays.stream(score).boxed().toArray(Integer[]::new);
Arrays.sort(arr, Collections.reverseOrder());
for (int i = 0; i < len; i++) {
// 길이를 m으로 나눠서 카운트 ㅓ장하고, 초기화
// 사과 점수 계싼 공식 Math.min(사과1, 사과2, 사과3, 사과4...) * m
// 여기 어떻게 처리>?
}
return answer;
}
}