알고리즘 leetcode │ 84. 히스토그램에서 가장 큰 직사각형 (녹이 심함)



84. 히스토그램에서 가장 큰 직사각형:

주어진 n 음수가 아닌 정수는 히스토그램의 각 열 높이를 나타내는 데 사용됩니다. 각 열은 서로 인접해 있으며 너비는 1 입니다.

이 히스토그램에서 그릴 수 있는 직사각형의 최대 면적을 구하십시오.

예시 1:

输入:

	heights = [2,1,5,6,2,3]
	
输出:
	
	10
	
解释:
	
	最大的矩形为图中红色区域,面积为 10

예시 2:

输入:
	
	 heights = [2,4]
	 
输出: 
	
	4

힌트:

  • 1 5
  • 0 <= 높이[i] <= 104

분석하다:

  • 이 알고리즘 질문에 직면한 두 번째 마스터는 다시 한 번 깊은 생각에 빠졌습니다.
  • 언뜻 보면 아이디어가 있는 것 같지만, 일단 막상 시작하면 어디서부터 시작해야 할지 막막하기 쉽습니다.
  • 이중 루프를 수행하여 각 열을 순회하여 왼쪽에서 자신보다 낮은 첫 번째 열과 오른쪽에서 자신보다 낮은 첫 번째 열을 찾습니다. 이 방법으로 현재 열 높이의 최대 너비를 계산할 수 있습니다. .. 단서가 있다면 분명히 매우 그럴 것입니다. 잠깐, 더 좋은 방법이 있을까요?
  • 각 열(자신보다 낮은 첫 번째 열)의 왼쪽 및 오른쪽 경계를 찾는 것이 핵심입니다. 검색 복잡도를 줄일 수 있는 방법이 있나요?
  • 한 번의 순회에서 왼쪽과 오른쪽 경계를 찾을 수 있다면 좋을 것입니다. 아티팩트 단조 스택을 사용합니다. 스택이 비어 있으면 스택에 푸시합니다(여기서 기술을 사용하여 처리 논리를 통합할 수 있습니다). 그렇지 않으면 판단합니다. 다음 기둥이 스택의 상단보다 높거나 스택의 상단과 같은지 여부 스택의 상단이 동일한 높이이면 스택으로 직접 푸시됩니다. 스택의 경우 현재 열이 스택 맨 위 요소의 오른쪽 경계이므로 스택에서 팝됩니다. 이 과정을 반복하면 한 번의 순회로 왼쪽 및 오른쪽 경계를 찾을 수 있습니다.
  • 순회 과정에서 스택이 비어 있는 상황, 모든 열을 순회했지만 스택이 비어 있지 않은 상황에 특히 주의하세요.

답변:

녹:

impl Solution {
    
    
    pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
    
    
        let mut ans = 0;

        let mut stack = vec![-1];
        let n = heights.len();
        (0..n).for_each(|i| {
    
    
            while stack.len() > 1 && heights[*stack.last().unwrap() as usize] > heights[i] {
    
    
                // 栈中比当前位置高的那些待确定右边界的下标都可以确定右边界了

                ans = ans.max(heights[stack.pop().unwrap() as usize] * (i as i32 - 1 - stack.last().unwrap()));
            }
            // 入栈,等到能够确定右边界时处理
            stack.push(i as i32);
        });

        while stack.len() > 1 {
    
    
            // 栈中剩余的都是右边没有更低的

            ans = ans.max(heights[stack.pop().unwrap() as usize] * (n as i32 - 1 - stack.last().unwrap()));
        }

        return ans;
    }
}

가다:

func largestRectangleArea(heights []int) int {
    
    
    max := func(x, y int) int {
    
    
		if x > y {
    
    
			return x
		}
		return y
	}

	ans := 0

	n := len(heights)
	stack := []int{
    
    -1}
	for i := 0; i < n; i++ {
    
    
		for len(stack) > 1 && heights[stack[len(stack)-1]] > heights[i] {
    
    
			// 栈中比当前位置高的那些待确定右边界的下标都可以确定右边界了

			ans = max(ans, heights[stack[len(stack)-1]]*(i-1-stack[len(stack)-2]))
			// 出栈
			stack = stack[:len(stack)-1]
		}
		// 入栈,等到能够确定右边界时处理
		stack = append(stack, i)
	}

	for len(stack) > 1 {
    
    
		// 栈中剩余的都是右边没有更低的

		ans = max(ans, heights[stack[len(stack)-1]]*(n-1-stack[len(stack)-2]))
		// 出栈
		stack = stack[:len(stack)-1]
	}

	return ans
}

C++:

class Solution {
    
    
public:
    int largestRectangleArea(vector<int>& heights) {
    
    
        int ans = 0;

        const int n = heights.size();
        stack<int> s;
        s.push(-1);
        for (int i = 0; i < n; ++i) {
    
    
            while (s.size() > 1 && heights[s.top()] > heights[i]) {
    
    
                // 栈中比当前位置高的那些待确定右边界的下标都可以确定右边界了

                int height = heights[s.top()];
                s.pop();
                ans = max(ans, height * (i - 1 - s.top()));
            }
            // 入栈,等到能够确定右边界时处理
            s.push(i);
        }

        while (s.size() > 1) {
    
    
            // 栈中剩余的都是右边没有更低的

            int height = heights[s.top()];
            s.pop();
            ans = max(ans, height * (n - 1 - s.top()));
        }

        return ans;
    }
};

파이썬:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        ans = 0

        n = len(heights)
        stack = [-1]
        for i in range(n):
            while len(stack) > 1 and heights[stack[-1]] > heights[i]:
                # 比当前位置高的那些待确定右边界的下标都可以确定右边界了
                ans = max(ans, heights[stack.pop()] * (i - 1 - stack[-1]))
            # 入栈,等到能够确定右边界时处理
            stack.append(i)
        while len(stack) > 1:
            # 栈中剩余的都是右边没有更低的
            ans = max(ans, heights[stack.pop()] * (n - 1 - stack[-1]))

        return ans


자바:

class Solution {
    
    
    public int largestRectangleArea(int[] heights) {
    
    
        int ans = 0;

        final int      n     = heights.length;
        Deque<Integer> stack = new LinkedList<>();
        stack.push(-1);
        for (int i = 0; i < n; ++i) {
    
    
            while (stack.size() > 1 && heights[stack.peek()] > heights[i]) {
    
    
                // 栈中比当前位置高的那些待确定右边界的下标都可以确定右边界了

                ans = Math.max(ans, heights[stack.pop()] * (i - 1 - stack.peek()));
            }
            // 入栈,等到能够确定右边界时处理
            stack.push(i);
        }

        while (stack.size() > 1) {
    
    
            // 栈中剩余的都是右边没有更低的

            ans = Math.max(ans, heights[stack.pop()] * (n - 1 - stack.peek()));
        }

        return ans;
    }
}

이 글을 읽어주셔서 정말 감사합니다~
[좋아요] [수집] [댓글] 3회 연속 환영합니다~
입니다 포기하는 것은 어렵지 않습니다. 그러나 인내심은 멋져야 합니다~
우리 모두 매일 조금씩 발전할 수 있기를 바랍니다~
이 기사는 원본 블로그~두 번째 보스의 흰모자: https://le-yi.blog.csdn.net/


추천

출처blog.csdn.net/leyi520/article/details/133166907