[프로그래머스] 최솟값 만들기 문제 예시
길이가 같은 배열 A, B 두개가 있습니다. 각 배열은 자연수로 이루어져 있습니다.
배열 A, B에서 각각 한 개의 숫자를 뽑아 두 수를 곱합니다. 이러한 과정을 배열의 길이만큼 반복하며, 두 수를 곱한 값을 누적하여 더합니다. 이때 최종적으로 누적된 값이 최소가 되도록 만드는 것이 목표입니다. (단, 각 배열에서 k번째 숫자를 뽑았다면 다음에 k번째 숫자는 다시 뽑을 수 없습니다.)
예를 들어 A = [1, 4, 2] , B = [5, 4, 4] 라면
- A에서 첫번째 숫자인 1, B에서 첫번째 숫자인 5를 뽑아 곱하여 더합니다. (누적된 값 : 0 + 5(1x5) = 5)
- A에서 두번째 숫자인 4, B에서 세번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 5 + 16(4x4) = 21)
- A에서 세번째 숫자인 2, B에서 두번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 21 + 8(2x4) = 29)
즉, 이 경우가 최소가 되므로 29를 return 합니다.
배열 A, B가 주어질 때 최종적으로 누적된 최솟값을 return 하는 solution 함수를 완성해 주세요.
제한사항
- 배열 A, B의 크기 : 1,000 이하의 자연수
- 배열 A, B의 원소의 크기 : 1,000 이하의 자연수
입출력 예
A | B | answer |
[1, 4, 2] | [5, 4, 4] | 29 |
[1,2] | [3,4] | 10 |
입출력 예 설명
입출력 예 #1
문제의 예시와 같습니다.
입출력 예 #2
A에서 첫번째 숫자인 1, B에서 두번째 숫자인 4를 뽑아 곱하여 더합니다. (누적된 값 : 4) 다음, A에서 두번째 숫자인 2, B에서 첫번째 숫자인 3을 뽑아 곱하여 더합니다. (누적된 값 : 4 + 6 = 10)
이 경우가 최소이므로 10을 return 합니다.
function solution(A,B){
let answer = [];
let sortA = A.sort((a,b) => a-b);
let sortB = B.sort((a,b) => b-a);
for (let i = 0; i < A.length; i++) {
answer.push(sortA[i] * sortB[i]);
}
return answer.reduce((acc, cur) => acc + cur, 0);
}
내가 위 문제를 푼 방식이다.
- 다른 풀이
function solution(A,B){
A.sort((a, b) => a - b)
B.sort((a, b) => b - a)
return A.reduce((total, val, idx) => total + val * B[idx], 0)
}
하지만 풀고 나서 다른 풀이를 참고해 보니 굳이 for문으로 index를 지정해 줄 필요가 없다!
0 초기값부터 시작해 A의 값과 B의 값을 index 순으로 곱하고 곱한 값을 하나씩 다 더해준다.
물론 reduce도 반복적인 방법으로 만들어진 메서드로 for문과 시간복잡도는 차이가 없겠지만 reduce 메서드를 사용하면 더 간단하게 표현하고 가독성을 높일 수도 있다.
▶ Array.prototype.reduce()
[참고] 2023.01.06 - [코테 문풀] - [프로그래머스] 자릿수 더하기 - JavaScript / reduce()에 대해 이해해보자!
이전 글에서도 reduce에 정리를 해놨었는데 currentIndex 매개변수를 사용하는 건 익숙하지 않았기 때문에 다시 정리하고 넘어가려고 한다.
const array = [15, 16, 17, 18, 19];
function reducer(accumulator, currentValue, index) {
const returns = accumulator + currentValue;
console.log(
`accumulator: ${accumulator}, currentValue: ${currentValue}, index: ${index}, returns: ${returns}`,
);
return returns;
}
array.reduce(reducer);
initialValue가 없이 사용할 때 예시 코드. index는 1부터 시작한다. (initialValue가 지정되면 0부터 시작한다)
매개변수
callbackFn
: 배열의 각 요소에 대해 실행할 함수. 반환 값은 accumulator이고 다음에 callbackFn를 호출할 때 매개변수의 값이 된다. 마지막 호출의 경우 반환 값은 reduce()의 반환 값이 됩니다.
accumulator은 callbackFn에 대한 이전 호출의 결과 값. 첫 번째 호출에서 initialValue가 지정된 경우 initialValue, 지정되지 않는다면 array[0]의 값.
currentValue는 현재 요소의 값. 첫 번째 호출에서 initialValue가 지정된 경우 array[0]의 값, 지정되지 않는다면 array[1]의 값(accumulator의 값이 array[0]이 되기 때문)
currentIndex는 currentValue 배열에서 인덱스 위치. 첫 번째 호출에서 initialValue가 지정되면 0, 아니면 1(initialValue가 0이므로).
array : array reduce()가 호출됨.
initialValue(선택)는 콜백이 처음 호출될 때 accumulator가 초기화되는 값. initialValue가 지정되면 callbackFn은 배열 첫 번째 값을 currentValue로 사용해 실행을 시작. initialValue가 지정되지 않은 경우 initialValue는 accumulator 배열의 첫 번째 값으로 초기화되고 배열의 두 번째 값을 currentValue을 지정해 실행을 시작. 이 경우 배열이 비어 있으면(accumulator로 반환할 첫 번째 값이 없음) 오류가 발생.(TypeError)
예시
객체 배열의 값 합계(Sum of values in an object array)
const objects = [{ x: 1 }, { x: 2 }, { x: 3 }];
const sum = objects.reduce(
(accumulator, currentValue) => accumulator + currentValue.x,
0,
);
console.log(sum); // 6
위와 같이 객체 array의 값의 합계도 구할 수 있다. currentValue.x로 key를 명시해 주면 된다.
배열의 배열 병합(Flatten an array of arrays)
const flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
// flattened is [0, 1, 2, 3, 4, 5]
초기값으로 []을 주고, 거기에 concat을 해가면 array를 병합할 수 있다.
객체에서 값의 인스턴스 계산(Counting instances of values in an object)
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = names.reduce((allNames, name) => {
const currCount = allNames[name] ?? 0;
return {
...allNames,
[name]: currCount + 1,
};
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
names의 배열 안에 각 name을 바로 count 해주는 방식
+ ▶ Nullish coalescing operator (??)
leftExpr ?? rightExpr
Nullish 병합 ?? 연산자는 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자이다.
const foo = null ?? 'default string';
console.log(foo);
// Expected output: "default string"
const baz = 0 ?? 42;
console.log(baz);
// Expected output: 0
속성별로 객체 그룹화(Grouping objects by a property)
const people = [
{ name: "Alice", age: 21 },
{ name: "Max", age: 20 },
{ name: "Jane", age: 20 },
];
function groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
const curGroup = acc[key] ?? [];
return { ...acc, [key]: [...curGroup, obj] };
}, {});
}
const groupedPeople = groupBy(people, "age");
console.log(groupedPeople);
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
각 obj를 지정해 주는 property대로(key) 분류해 해당 key를 가진 obj를 array로 묶어 반환하는 groupBy 함수를 만들고, "age"를 property로 지정해 주면 나이별로 people을 group 할 수 있다.
확산 구문(...) 및 initialValue를 사용하여 객체 배열에 포함된 배열 연결(Concatenating arrays contained in an array of objects using the spread syntax and initialValue)
// friends - an array of objects
// where object field "books" is a list of favorite books
const friends = [
{
name: "Anna",
books: ["Bible", "Harry Potter"],
age: 21,
},
{
name: "Bob",
books: ["War and peace", "Romeo and Juliet"],
age: 26,
},
{
name: "Alice",
books: ["The Lord of the Rings", "The Shining"],
age: 18,
},
];
// allbooks - list which will contain all friends' books +
// additional list contained in initialValue
const allbooks = friends.reduce(
(accumulator, currentValue) => [...accumulator, ...currentValue.books],
["Alphabet"],
);
console.log(allbooks);
// [
// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
// 'Romeo and Juliet', 'The Lord of the Rings',
// 'The Shining'
// ]
초기값을 ["Alphabet"]로 줘서 같이 넣어주고 ...currentValue.books로 obj에서 books를 지정해 books만 새로운 배열에 넣어줬다.
참고로 accumulator에 concat 같은 역할을 하는 ...을 적어주지 않으면 배열 안에 계속 배열이 추가되는 형태로 들어가 버린다.
currentValue.book에 ...을 적어주지 않으면 ['Alphabet', Array(2), Array(2), Array(2)] 형태로 Array 그대로 들어가 버린다.
[참고] 2023.01.12 - [코테 문풀] - [프로그래머스] 등수 매기기 - JavaScript / ES6 ... 연산자란? 사용 예시
배열에서 중복 항목 제거(Remove duplicate items in an array)
const myArray = ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
const myArrayWithNoDuplicates = myArray.reduce((accumulator, currentValue) => {
if (!accumulator.includes(currentValue)) {
return [...accumulator, currentValue];
}
return accumulator;
}, []);
console.log(myArrayWithNoDuplicates); // ['a', 'b', 'c', 'e', 'd']
※ 참고로 같은 효과인 const arrayWithNoDuplicates = Array.from(new Set(myArray)) 이런 식으로 Array.from, Set을 사용하는 것이 더 좋은 성능을 낸다.
모든 코드 예시는 mdn 문서에서 가져왔습니다. 메서드의 다양한 활용 방식을 정리해 두면 계속 도움이 된다!
🙂 공부하면서 정리한 글입니다. 공감과 피드백 환영합니다.
'프로그래밍 > JavaScript' 카테고리의 다른 글
[JS] Hosting 호이스팅이란? / 프로그래머스 구명보트 예시 문제 풀이 (0) | 2023.01.27 |
---|---|
[JS] JavaScript에서 Number, 문자열 진법 자유롭게 변환하기 / 3진법 뒤집기 (0) | 2023.01.25 |
[Js] Array에서 순서 변경하지 않고 특정 값 삭제하기 🧚🏻♀️ / 제일 작은 수 제거하기 (0) | 2023.01.21 |
[Js] 구조 분해 할당(Destructuring assignment)이란? (1) | 2023.01.18 |
[JS] this는 도대체 뭘까? this의 개념과 예시 문제 풀이 (0) | 2023.01.17 |