Home 백준 - 6549 히스토그램에서 가장 큰 직사각형 풀이
Post
Cancel

백준 - 6549 히스토그램에서 가장 큰 직사각형 풀이

문제

6549 히스토그램에서 가장 큰 직사각형

screencaptures

스택 사용 방법

풀이

개념

kotlin code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
fun main() {
    val inputList = mutableListOf<IntArray>()
    while (true)
    {
        val line = readln().trim()
        if(line == "0") break
        if(line.isEmpty()) continue
        inputList.add(line.split(" ").drop(1).map { it.toInt() }.toIntArray())
    }

    for(histogram in inputList) {
        println(getMaxArea(histogram))
    }
}

fun getMaxArea(histogram: IntArray): Long {
    val stack = java.util.Stack<Int>()
    var max = 0L
    for((index, curHeight) in histogram.withIndex()) {
        max = getMaxArea(index, max, stack, histogram, curHeight)
        stack.push(index)
    }
    while(stack.isNotEmpty()) {
        max = getMaxArea(histogram.size, max, stack, histogram)
    }
    return max
}

private fun getMaxArea(index: Int, curMax: Long, stack: java.util.Stack<Int>, histogram: IntArray, curHeight: Int = -1): Long {
    var max = curMax
    while (stack.isNotEmpty() && curHeight <= histogram[stack.peek()]) {
        val height = histogram[stack.pop()].toLong()
        val width = (index - stack.peekOrDefault() - 1)
        max = kotlin.math.max(max, height * width)
    }
    return max
}

fun java.util.Stack<Int>.peekOrDefault(defaultValue: Int = -1): Int = when {
    empty() -> defaultValue
    else -> this.peek()
}

분할 정복법

풀이

개념

kotlin code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
fun main() {
    val inputList = mutableListOf<IntArray>()
    while (true)
    {
        val line = readln().trim()
        if(line == "0") break
        if(line.isEmpty()) continue
        inputList.add(line.split(" ").drop(1).map { it.toInt() }.toIntArray())
    }

    for(histogram in inputList) {
        println(getMaxArea(0, histogram.size, histogram))
    }
}

fun getMaxArea(fromIndex: Int, toIndex: Int, histogram: IntArray): Long = when(fromIndex) {
    toIndex - 1 -> histogram[fromIndex].toLong()
    else -> {
        val midIndex = (fromIndex + toIndex) / 2
        val leftMaxArea = getMaxArea(fromIndex, midIndex, histogram)
        val rightMaxArea = getMaxArea(midIndex, toIndex, histogram)
        val midMaxArea = getMidMaxArea(fromIndex, toIndex, midIndex, histogram)
        kotlin.math.max(kotlin.math.max(leftMaxArea, rightMaxArea), midMaxArea)
    }

}

fun getMidMaxArea(fromIndex: Int, toIndex: Int, midIndex: Int, histogram: IntArray): Long {
    var leftIndex = midIndex
    var rightIndex = midIndex
    val lastIndex = toIndex - 1

    var height = histogram[midIndex].toLong()
    var maxArea = height


    while (fromIndex < leftIndex && rightIndex < lastIndex) {
        if(height == 0L || maxArea > (toIndex - fromIndex) * height) return maxArea
        val curHeight =
            if (histogram[leftIndex - 1] >= histogram[rightIndex + 1]) histogram[--leftIndex].toLong()
            else histogram[++rightIndex].toLong()
        if (curHeight < height) height = curHeight
        val width = rightIndex - leftIndex + 1
        val area = height * width
        if (area > maxArea) maxArea = area
    }

    while (fromIndex < leftIndex) {
        if(height == 0L || maxArea > (toIndex - fromIndex) * height) return maxArea
        val curHeight = histogram[--leftIndex].toLong()
        if (curHeight < height) height = curHeight
        val width = rightIndex - leftIndex + 1
        val area = height * width
        if (area > maxArea) maxArea = area
    }

    while (rightIndex < lastIndex) {
        if(height == 0L || maxArea > (toIndex - fromIndex) * height) return maxArea
        val curHeight = histogram[++rightIndex].toLong()
        if (curHeight < height) height = curHeight
        val width = rightIndex - leftIndex + 1
        val area = height * width
        if (area > maxArea) maxArea = area
    }
    return maxArea
}

Segment Tree + 분할 정복법

풀이

개념

kotlin code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
fun main() {
    val inputList = mutableListOf<IntArray>()
    while (true)
    {
        val line = readln().trim()
        if(line == "0") break
        if(line.isEmpty()) continue
        inputList.add(line.split(" ").drop(1).map { it.toInt() }.toIntArray())
    }

    for(histogram in inputList) {
        println(getMaxArea(histogram))
    }
}

fun getMaxArea(histogram: IntArray): Long {
    val segmentTree = getSegmentTree(histogram)

    return getMaxArea(0, histogram.size, segmentTree, histogram)
}

fun getMaxArea(startIndex: Int, endIndex: Int, segmentTree: IntArray, histogram: IntArray): Long = when {
    startIndex == endIndex - 1 -> histogram[startIndex].toLong() * (endIndex - startIndex)
    startIndex >= endIndex -> 0L
    else -> {
        val minIndex = getMinIndex(0, 0, histogram.size, startIndex, endIndex, segmentTree, histogram)
        val leftArea = getMaxArea(startIndex, minIndex, segmentTree, histogram)
        val rightArea = getMaxArea(minIndex + 1, endIndex, segmentTree, histogram)
        val thisArea = histogram[minIndex].toLong() * (endIndex - startIndex)
        kotlin.math.max(kotlin.math.max(leftArea, rightArea), thisArea)
    }
}

fun Int.getLeftNode() = this * 2 + 1

fun Int.getRightNode() = this * 2 + 2

fun getMinIndex(node: Int, histogramFromIndex: Int, histogramToIndex: Int, targetFromIndex: Int, targetToIndex: Int, segmentTree: IntArray, histogram: IntArray): Int {
    if(targetToIndex <= histogramFromIndex || histogramToIndex <= targetFromIndex) return -1
    if(histogramFromIndex >= targetFromIndex && targetToIndex >= histogramToIndex) return segmentTree[node]

    val histogramMidIndex = kotlin.math.ceil((histogramFromIndex + histogramToIndex) / 2.0).toInt()
    val leftIndex = getMinIndex(
        node.getLeftNode(),
        histogramFromIndex,
        histogramMidIndex,
        targetFromIndex,
        targetToIndex,
        segmentTree,
        histogram
    )
    val rightIndex = getMinIndex(
        node.getRightNode(),
        histogramMidIndex,
        histogramToIndex,
        targetFromIndex,
        targetToIndex,
        segmentTree,
        histogram
    )

    if(leftIndex == -1) return rightIndex
    if(rightIndex == -1) return leftIndex
    return if(histogram[leftIndex] <= histogram[rightIndex]) leftIndex else  rightIndex
}

private fun getSegmentTree(histogram: IntArray): IntArray {
    val segmentTree = IntArray(histogram.getTreeSize()) { -1 }
    initTree(0, 0, histogram.size, segmentTree, histogram)
    return segmentTree
}

private fun initTree(node: Int, startIndex: Int, endIndex: Int, segmentTree: IntArray, histogram: IntArray): Int = when (startIndex) {
    endIndex - 1 -> {
        segmentTree[node] = startIndex
        segmentTree[node]
    }
    else -> {
        val midIndex = getTreeMidIndex(startIndex, endIndex)
        val left = initTree(node.getLeftNode(), startIndex, midIndex, segmentTree, histogram)
        val right = initTree(node.getRightNode(), midIndex, endIndex, segmentTree, histogram)
        segmentTree[node] = if(histogram[left] <= histogram[right]) left else right
        segmentTree[node]
    }
}

private fun IntArray.getTreeSize() = Math.pow(2.0, kotlin.math.ceil(kotlin.math.log2(this.size.toDouble()))).toInt() * 2 - 1

private fun getTreeMidIndex(startIndex: Int, endIndex: Int) = kotlin.math.ceil((startIndex + endIndex) / 2.0).toInt()

Attachments

This post is licensed under CC BY 4.0 by the author.

백준 - 10830 행렬 제곱

백준 - 17478 재귀함수가 뭔가요?