Skip to content

Commit 499935e

Browse files
authored
2025년 16주차 문제 풀이 (#43)
## 문제 풀이 목록 - [LeetCode 2145. Count the Hidden Sequences](https://leetcode.com/problems/count-the-hidden-sequences) :sparkles: - [LeetCode 2338. Count the Number of Ideal Arrays](https://leetcode.com/problems/count-the-number-of-ideal-arrays) ✨ - [LeetCode 1399. Count Largest Group](https://leetcode.com/problems/count-largest-group) - [LeetCode 2799. Count Complete Subarrays in an Array](https://leetcode.com/problems/count-complete-subarrays-in-an-array) ✨ - [LeetCode 2845. Count of Interesting Subarrays](https://leetcode.com/problems/count-of-interesting-subarrays) ✨ - [LeetCode 2444. Count Subarrays With Fixed Bounds](https://leetcode.com/problems/count-subarrays-with-fixed-bounds) - [LeetCode 3392. Count Subarrays of Length Three With a Condition](https://leetcode.com/problems/count-subarrays-of-length-three-with-a-condition)
1 parent 03375a6 commit 499935e

File tree

23 files changed

+1119
-422
lines changed

23 files changed

+1119
-422
lines changed

solution/README.md

Lines changed: 369 additions & 365 deletions
Large diffs are not rendered by default.

solution/src/leetcode/1399/1399.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@
33
* https://leetcode.com/problems/count-largest-group
44
*/
55
export function countLargestGroup(n: number): number {
6-
const sumOfDigits = (n: number) => {
7-
return n
8-
.toString()
9-
.split('')
10-
.reduce((sum, digit) => sum + +digit, 0);
11-
};
12-
const groups = new Map<number, number>();
6+
let groupCount = 0;
137
let largestGroupSize = 0;
14-
for (let i = 1; i <= n; i++) {
15-
const group = sumOfDigits(i);
16-
const groupSize = (groups.get(group) ?? 0) + 1;
17-
groups.set(group, groupSize);
18-
largestGroupSize = Math.max(groupSize, largestGroupSize);
8+
const group = new Map<number, number>();
9+
for (let num = 1; num <= n; num++) {
10+
const sum = sumOfDigits(num);
11+
const groupSize = (group.get(sum) ?? 0) + 1;
12+
group.set(sum, groupSize);
13+
14+
if (groupSize > largestGroupSize) {
15+
largestGroupSize = groupSize;
16+
groupCount = 1;
17+
} else if (groupSize === largestGroupSize) {
18+
groupCount += 1;
19+
}
1920
}
21+
return groupCount;
22+
}
2023

21-
return [...groups.values()].filter((groupSize) => groupSize === largestGroupSize).length;
24+
function sumOfDigits(num: number): number {
25+
let result = 0;
26+
let curr = num;
27+
while (curr > 0) {
28+
result += curr % 10;
29+
curr = Math.floor(curr / 10);
30+
}
31+
return result;
2232
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { numberOfArrays } from './2145';
2+
3+
describe('LeetCode 2145', () => {
4+
test('Example 1', () => {
5+
expect(numberOfArrays([1, -3, 4], 1, 6)).toBe(2);
6+
});
7+
test('Example 2', () => {
8+
expect(numberOfArrays([3, -4, 5, 1, -2], -4, 5)).toBe(4);
9+
});
10+
test('Example 3', () => {
11+
expect(numberOfArrays([4, -7, 2], 3, 6)).toBe(0);
12+
});
13+
});

solution/src/leetcode/2145/2145.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* 2145. Count the Hidden Sequences
3+
* https://leetcode.com/problems/count-the-hidden-sequences
4+
*/
5+
export function numberOfArrays(differences: number[], lower: number, upper: number): number {
6+
const rangeSize = upper - lower;
7+
8+
let minValue = 0;
9+
let maxValue = 0;
10+
let currentValue = 0;
11+
for (const difference of differences) {
12+
currentValue += difference;
13+
minValue = Math.min(minValue, currentValue);
14+
maxValue = Math.max(maxValue, currentValue);
15+
// 최대값과 최소값의 차이가 기존의 범위 크기 보다 크다면 `hidden`은 존재할 수 없다.
16+
if (maxValue - minValue > rangeSize) {
17+
return 0;
18+
}
19+
}
20+
21+
// 기존의 범위 내에서 시작점을 이동시킬 수 있는 범위의 크기
22+
return rangeSize - (maxValue - minValue) + 1;
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "2145",
3+
"url": "https://leetcode.com/problems/count-the-hidden-sequences",
4+
"title": "Count the Hidden Sequences",
5+
"category": "Algorithms",
6+
"difficulty": "Medium",
7+
"tags": ["Array", "Prefix Sum"]
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { idealArrays } from './2338';
2+
3+
describe('LeetCode 2338', () => {
4+
test('Example 1', () => {
5+
expect(idealArrays(2, 5)).toBe(10);
6+
});
7+
test('Example 2', () => {
8+
expect(idealArrays(5, 3)).toBe(11);
9+
});
10+
});

solution/src/leetcode/2338/2338.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* 2338. Count the Number of Ideal Arrays
3+
* https://leetcode.com/problems/count-the-number-of-ideal-arrays
4+
*/
5+
export function idealArrays(n: number, maxValue: number): number {
6+
const MOD = 10 ** 9 + 7;
7+
8+
/**
9+
* 점점 증가하는 이상적인 배열의 최대 길이는 14입니다.
10+
* 2^14 > 10,000 가능한 가장 긴 점점 증가하는 이상적 배열은 [1, 2, 4, 8, ..., 8192]입니다.
11+
*/
12+
const MAX_LEN = Math.min(n, 14);
13+
14+
// dp[i][j]는 길이 i의 j로 끝나는 이상적인 배열의 개수
15+
const dp = Array.from({ length: MAX_LEN + 1 }, () => new Array<number>(maxValue + 1).fill(0));
16+
17+
// `maxValue`까지 모든 수에 대한 약수
18+
const divisors = getDivisors(maxValue);
19+
20+
// 길이가 1인 이상적인 배열의 개수는 1로 초기화합니다.
21+
for (let i = 1; i <= maxValue; i++) {
22+
dp[1][i] = 1;
23+
}
24+
25+
/**
26+
* dp[i][j] = sum(dp[i-1][k])
27+
* 단, j는 k로 나누어 떨어져야 함 (즉, k는 j의 약수)
28+
*/
29+
for (let i = 2; i <= MAX_LEN; i++) {
30+
for (let j = 1; j <= maxValue; j++) {
31+
for (const k of divisors.get(j) ?? []) {
32+
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
33+
}
34+
}
35+
}
36+
37+
// dp[i][0] = 길이가 i인 점점 증가하는 이상적인 배열의 개수
38+
for (let i = 1; i <= MAX_LEN; i++) {
39+
for (let j = 1; j <= maxValue; j++) {
40+
dp[i][0] = (dp[i][0] + dp[i][j]) % MOD;
41+
}
42+
}
43+
44+
/**
45+
* 조합론을 사용한, 길이가 i인 점점 증가하는 이상적인 배열의 개수로부터
46+
* 길이가 n인 증가하는 이상적인 배열의 총 개수를 도출
47+
*/
48+
let answer = 0n;
49+
for (let i = 1; i <= MAX_LEN; i++) {
50+
answer += nCk(n - 1, i - 1) * BigInt(dp[i][0]);
51+
answer %= BigInt(MOD);
52+
}
53+
return Number(answer);
54+
}
55+
56+
// "n Choose k"를 계산
57+
function nCk(n: number, k: number): bigint {
58+
let result = 1n;
59+
for (let i = 1; i <= k; i++) {
60+
result = (result * BigInt(n - (i - 1))) / BigInt(i);
61+
}
62+
return result;
63+
}
64+
65+
// `maxValue`까지의 모든 수에 대한 약수들을 계산
66+
function getDivisors(maxValue: number): Map<number, number[]> {
67+
const divisors = new Map<number, number[]>();
68+
for (let value = 1; value <= maxValue; value++) {
69+
divisors.set(value, []);
70+
}
71+
for (let value = 1; value <= maxValue; value++) {
72+
let multiply = 2;
73+
while (value * multiply <= maxValue) {
74+
divisors.get(value * multiply)?.push(value);
75+
multiply += 1;
76+
}
77+
}
78+
return divisors;
79+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "2338",
3+
"url": "https://leetcode.com/problems/count-the-number-of-ideal-arrays",
4+
"title": "Count the Number of Ideal Arrays",
5+
"category": "Algorithms",
6+
"difficulty": "Hard",
7+
"tags": ["Math", "Dynamic Programming", "Combinatorics", "Number Theory"]
8+
}

solution/src/leetcode/2444/2444.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@
33
* https://leetcode.com/problems/count-subarrays-with-fixed-bounds
44
*/
55
export function countSubarrays(nums: number[], minK: number, maxK: number): number {
6-
let answer = 0;
6+
const n = nums.length;
77

8-
let minIndex = -1;
9-
let maxIndex = -1;
10-
let outIndex = -1;
11-
nums.forEach((num, i) => {
12-
if (num < minK || maxK < num) {
13-
outIndex = i;
8+
let answer = 0;
9+
let start = 0;
10+
let lastMinIndex = -1;
11+
let lastMaxIndex = -1;
12+
for (let i = 0; i < n; i++) {
13+
const num = nums[i];
14+
if (num < minK || num > maxK) {
15+
start = i + 1;
16+
}
17+
if (num === maxK) {
18+
lastMaxIndex = i;
1419
}
1520
if (num === minK) {
16-
minIndex = i;
21+
lastMinIndex = i;
1722
}
18-
if (num === maxK) {
19-
maxIndex = i;
23+
if (start <= lastMinIndex && start <= lastMaxIndex) {
24+
answer += Math.min(lastMinIndex, lastMaxIndex) - start + 1;
2025
}
21-
answer += Math.max(0, Math.min(minIndex, maxIndex) - outIndex);
22-
});
23-
26+
}
2427
return answer;
2528
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { countCompleteSubarrays } from './2799';
2+
3+
describe('LeetCode 2799', () => {
4+
test('Example 1', () => {
5+
expect(countCompleteSubarrays([1, 3, 1, 2, 2])).toBe(4);
6+
});
7+
test('Example 2', () => {
8+
expect(countCompleteSubarrays([5, 5, 5, 5])).toBe(10);
9+
});
10+
});

0 commit comments

Comments
 (0)