정렬 게임
https://www.acmicpc.net/problem/1715
// 카드 정렬하기
function jungyeolGame(str) {
let a = str.split("\n");
console.log(a);
// 수열의 개수
const count = a[0];
a.shift();
// 수열들
let arr = a[0].split(" ");
a.shift();
// 세트의 개수 K
let setCount = a[0];
a.shift();
// 네번쨰 줄 부터는 한 줄에 한 개씩 오름차순,내림차순순 // 여기터는 카운드들
let set = [...a];
console.log(set);
function sortFunc(asc, desc) {
let temArr = arr;
let tempArr2 = arr;
let a2 = temArr.slice(0, asc).sort((a, b) => a - b);
let b2 = tempArr2.slice(asc);
let tempAnswer = [...a2, ...b2];
let temDesc1 = tempAnswer;
let temDesc2 = tempAnswer;
let c = temDesc1.slice(0, desc).sort((a, b) => b - a);
let d = temDesc2.slice(desc);
return [...c, ...d].join(" ");
//asc 지점까지만 오름차순 실행
}
let answer = "";
for (let i = 0; i < setCount; i++) {
console.log("찍힘");
let temp = set[i].split(" ");
let asc = parseInt(temp[0]);
let desc = parseInt(temp[1]);
let result = sortFunc(asc, desc);
answer += i === setCount - 1 ? result : result + "\n";
}
return answer;
}
function jungyeolGame(str) {
let a = str.trim().split("\n");
// 수열 배열
let arr = a[1].split(" ").map(Number);
// 세트의 개수 K
let setCount = parseInt(a[2], 10);
// 오름차순, 내림차순 범위 정보
let operations = a.slice(3).map(op => op.split(" ").map(Number));
// 정렬 세트를 반복
for (let i = 0; i < setCount; i++) {
let [asc, desc] = operations[i];
// 오름차순 정렬
let ascSorted = arr.slice(0, asc).sort((a, b) => a - b);
// 정렬된 부분과 나머지 결합
arr = [...ascSorted, ...arr.slice(asc)];
// 내림차순 정렬
let descSorted = arr.slice(0, desc).sort((a, b) => b - a);
// 정렬된 부분과 나머지 결합
arr = [...descSorted, ...arr.slice(desc)];
}
// 최종 결과 반환
return arr.join(" ");
}
순회 강연
https://www.acmicpc.net/problem/2109
function circuitUniv(arr) {
// day순으로 정렬
arr.sort((a, b) => a.day - b.day);
// 강의의 최대 남은 기간 찾기
let maxDate = Math.max(...arr.map((item) => item.day));
// 끼워넣을 날짜를 만들어준다.
const arr2 = new Array(maxDate + 1).fill(0);
for (let i = 0; i < arr.length; i++) {
// 강의의 남은 기간을 거꾸로 검사
for (let j = arr[i].day; j > 0; j--) {
arr2[j] = Math.max(arr2[j], arr2[j - 1] + arr[i].pay);
}
}
console.log("arr2", arr2);
return Math.max(...arr2); // 최종 최대 수익 반환
}
// 예시 데이터
console.log(
circuitUniv([
{ pay: 20, day: 1 },
{ pay: 2, day: 1 },
{ pay: 10, day: 3 },
{ pay: 100, day: 2 },
{ pay: 8, day: 2 },
{ pay: 5, day: 20 },
{ pay: 50, day: 10 },
])
);
수열의 점수
https://www.acmicpc.net/problem/2036
문제
n개의 정수로 이루어진 수열이 있다. 이 수열에서 한 정수를 제거하거나, 또는 두 정수를 제거할 수 있다. 한 정수를 제거하는 경우에는 그 정수가 점수가 되고, 두 정수를 제거하는 경우에는 두 정수의 곱이 점수가 된다. 이를 반복하여 수열에 아무 수도 남지 않게 되었을 때, 점수의 총 합의 최대를 구하는 프로그램을 작성하시오.
예를 들어 -1, 5, -3, 5, 1과 같은 수열이 있다고 하자. 먼저 1을 제거하고, 다음으로는 5와 5를 제거하고, 다음에는 -1과 -3을 제거했다고 하자. 이 경우 각각 점수가 1, 25, 3이 되어 총 합이 29가 된다.
입력
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 줄에는 절댓값이 1,000,000을 넘지 않는 정수가 n개 주어진다.
출력
첫째 줄에 최대 점수를 출력한다.
function score(array) {
// 한 개의 정수 제거 => 이 정수가 점수가 됨
// 두 개의 정수를 제거 =>두 정수의 곱이 점수가 됨
// 이걸 반복해서 아무 수도 남지 않게 됐을 떄 , 점수의 총 합의 최대를 구하는 프로그램
// 내림 차순 정렬
let answer = 0;
array.sort((a, b) => a - b);
let negative = [];
let positive = [];
array.forEach((element) => {
if (element < 0) {
negative.push(element);
} else {
positive.push(element);
}
});
positive.reverse();
while (positive.length !== 0) {
// 1이면 그냥 더하기
if (positive[0] === 1) {
answer += positive[0];
positive.shift();
}
//1은 아니지먄 뒤에가 없으면 그냥 더하기
else if (positive[0] && positive[0] !== 1 && !positive[1]) {
answer += positive[0];
positive.shift();
}
// [0]이 1은 아니고 뒤에 [1]도 있지만, 1인 경우는 그냥 더하기
else if (
positive[0] &&
positive[0] !== 1 &&
positive[1] &&
positive[1] === 1
) {
answer += positive[0];
positive.shift();
}
// [0]이 1이 아니고 [1]도 1 넘으면 곱해서 더하기
else if (positive[0] && positive[0] > 1 && positive[1] && positive[1] > 1) {
answer += positive[0] * positive[1];
positive.shift();
positive.shift();
}
console.log(positive);
}
console.log("po answer", answer);
while (negative.length !== 0) {
if (negative[0] && negative[1]) {
answer += negative[0] * negative[1];
// 앞의 두 요소를 제거
negative.shift();
negative.shift();
} else {
console.log("negative[0]", negative[0]);
answer += negative[0];
// 앞의 한 요소만 제거
negative.shift();
}
}
console.log("answer", answer);
}
score([5, -1, 5, -3, 5, 1]);
function score(array) {
let answer = 0;
// 배열을 음수, 양수, 0으로 나누어 처리
let negative = [];
let positive = [];
let oneCount = 0; // 1을 따로 카운트
array.forEach((element) => {
if (element < 0) {
negative.push(element);
} else if (element === 1) {
oneCount++; // 1은 따로 더함
} else if (element > 0) {
positive.push(element);
}
});
// 음수는 오름차순으로 정렬 (작은 수일수록 두 개 곱했을 때 값이 커짐)
negative.sort((a, b) => a - b);
// 양수는 내림차순으로 정렬 (큰 수일수록 두 개 곱했을 때 값이 커짐)
positive.sort((a, b) => b - a);
// 1 처리 (1은 무조건 더하는 게 유리)
answer += oneCount;
// 양수 처리
while (positive.length > 1) {
// 두 개씩 묶어서 곱한 값을 더함
answer += positive[0] * positive[1];
positive.shift();
positive.shift();
}
// 양수가 하나 남아 있으면 더함
if (positive.length === 1) {
answer += positive[0];
}
// 음수 처리
while (negative.length > 1) {
// 두 개씩 묶어서 곱한 값을 더함
answer += negative[0] * negative[1];
negative.shift();
negative.shift();
}
// 음수가 하나 남아 있으면 그냥 더함
if (negative.length === 1) {
answer += negative[0];
}
return answer;
}
console.log(score([5, -1, 5, -3, 5, 1])); // 34
shift() 호출로 인해 배열의 앞쪽 요소를 제거하는데, 이는 O(n)의 시간 복잡도를 가지므로 반복적으로 수행할 경우 성능 저하가 발생합니다.shift()를 호출할 때마다 배열의 모든 요소를 한 칸씩 이동해야 하므로, 최악의 경우 O(n²)로 시간이 걸릴 수 있습니다.shift() 대신 slice()를 사용하거나 단순한 인덱스를 통해 배열의 요소를 접근하여 처리합니다.while 문을 통해 같은 패턴을 반복 처리하여 코드가 간단해졌습니다.oneCount를 따로 처리하여 1을 다루는 방식을 명확하게 하였습니다.| 요소 | 내 풀이 | 개선된 풀이 |
|---|---|---|
| 시간 복잡도 | O(n²) | O(n log n) |
| 가독성 | 중복된 조건, 복잡한 로직 | 간결한 로직, 명확한 처리 |
| 유지보수성 | 어려움 | 용이 |
개선된 풀이는 속도와 가독성 면에서 모두 우수합니다. 특히 대량의 데이터에 대한 성능 차이가 크게 나타날 수 있으므로, 가능한 효율적인 알고리즘을 선택하는 것이 중요합니다. 복잡성을 줄이고 가독성을 높이기 위해 불필요한 로직을 제거하고, 반복적인 패턴을 명확하게 처리하는 것이 좋은 코드 작성에 도움이 됩니다.
마무리