zoukankan      html  css  js  c++  java
  • LeetCode题目练习记录 _栈、队列01 _20211012

    LeetCode题目练习记录 _栈、队列01 _20211012

    84. 柱状图中最大的矩形

    难度困难1581

    给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

    求在该柱状图中,能够勾勒出来的矩形的最大面积。

    示例 1:

    img

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

    示例 2:

    img

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

    提示:

    • 1 <= heights.length <=105
    • 0 <= heights[i] <= 104

    方法一:单调栈

    class Solution {
        public int largestRectangleArea(int[] heights) {
            int n = heights.length;
            int[] left = new int[n];
            int[] right = new int[n];
    
            Deque<Integer> mono_stack = new ArrayDeque<Integer>();
            for(int i = 0; i < n; i++) {
                while(!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                    mono_stack.pop();
                }
                left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
                mono_stack.push(i); 
            }
            mono_stack.clear();
            for(int i=n-1; i >=0; i--) {
                while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                    mono_stack.pop();
                }
                right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
                mono_stack.push(i);
            }
            int ans = 0;
            for (int i = 0; i < n; i++) {
                ans = Math.max(ans,(right[i] - left[i] - 1) * heights[i]);
            }
            return ans;
        }
    }
    
    func largestRectangleArea(heights []int) int {
        n := len(heights)
        left, right := make([]int, n), make([]int, n)
        mono_stack := []int{}
        for i := 0; i < n; i++ {
            for len(mono_stack) > 0 && heights[mono_stack[len(mono_stack)-1]] >= heights[i] {
                mono_stack = mono_stack[:len(mono_stack)-1]
            }
            if len(mono_stack) == 0 {
                left[i] = -1
            }else{
                left[i] = mono_stack[len(mono_stack)-1]
            }
            mono_stack = append(mono_stack, i)
        }
        mono_stack = []int{}
        for i := n -1; i >= 0; i-- {
            for len(mono_stack) > 0 && heights[mono_stack[len(mono_stack) -1]] >= heights[i] {
                mono_stack = mono_stack[:len(mono_stack) -1]
            }
            if len(mono_stack) == 0 {
                right[i] = n
            }else {
                right[i] = mono_stack[len(mono_stack) -1]
            }
            mono_stack = append(mono_stack, i)
        }
        ans := 0
        for i := 0; i < n; i++ {
            ans = max(ans, (right[i] - left[i] -1) * heights[i])
        }
        return ans
    }
    
    func max(x,y int) int {
        if x > y {
            return x
        }
        return y
    }
    

    239. 滑动窗口最大值

    难度困难1215

    给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

    返回滑动窗口中的最大值。

    示例 1:

    输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
    输出:[3,3,5,5,6,7]
    解释:
    滑动窗口的位置                最大值
    ---------------               -----
    [1  3  -1] -3  5  3  6  7       3
     1 [3  -1  -3] 5  3  6  7       3
     1  3 [-1  -3  5] 3  6  7       5
     1  3  -1 [-3  5  3] 6  7       5
     1  3  -1  -3 [5  3  6] 7       6
     1  3  -1  -3  5 [3  6  7]      7
    

    示例 2:

    输入:nums = [1], k = 1
    输出:[1]
    

    示例 3:

    输入:nums = [1,-1], k = 1
    输出:[1,-1]
    

    示例 4:

    输入:nums = [9,11], k = 2
    输出:[11]
    

    示例 5:

    输入:nums = [4,-2], k = 2
    输出:[4]
    

    提示:

    • 1 <= nums.length <= 105
    • -104 <= nums[i] <= 104
    • 1 <= k <= nums.length

    方法一:优先队列

    class Solution {
        // Java 方法一:优先队列
        public int[] maxSlidingWindow(int[] nums, int k) {
            int n = nums.length;
            PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>(){
                public int compare(int[] pair1,int[] pair2){
                    return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
                }
            });
            for (int i = 0; i < k; i++) {
                pq.offer(new int[]{nums[i],i});
            }
            int[] ans = new int[n - k + 1];
            ans[0] = pq.peek()[0];
            for (int i = k; i < n; i++) {
                pq.offer(new int[]{nums[i], i});
                while (pq.peek()[1] <= i -k) {
                    pq.poll();
                }
                ans[i - k +1] = pq.peek()[0];
            }
            return ans;
        }
    }
    
    // Go 方法一:优先队列
    var a []int
    type hp struct{ sort.IntSlice }
    func (h hp)Less(i, j int)bool { 
        return a[h.IntSlice[i]] > a[h.IntSlice[j]] 
        }
    func (h *hp) Push(v interface{}) { 
        h.IntSlice = append(h.IntSlice, v.(int)) 
        }
    func (h *hp) Pop() interface{} { 
        a := h.IntSlice
        v := a[len(a)-1] 
        h.IntSlice = a[:len(a)-1]
        return v
        }
    func maxSlidingWindow(nums []int, k int) []int {
        a = nums
        q := &hp{make([]int,k)}
        for i := 0; i < k; i++ {
            q.IntSlice[i] = i
        }
        heap.Init(q)
    
        n := len(nums)
        ans := make([]int, 1, n-k+1)
        ans[0] = nums[q.IntSlice[0]]
        for i := k; i < n; i++ {
            heap.Push(q, i)
            for q.IntSlice[0] <= i-k {
                heap.Pop(q)
            }
            ans = append(ans,nums[q.IntSlice[0]])
        }
        return ans
    }
    

    方法二:单调队列

    class Solution {
        // Java 方法二:单调队列
        public int[] maxSlidingWindow(int[] nums, int k) {
            int n = nums.length;
            Deque<Integer> deque = new LinkedList<Integer>();
            for (int i = 0; i < k; i++) {
                while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                    deque.pollLast();
                }
                deque.offerLast(i);
            }
    
            int[] ans = new int[n - k + 1];
            ans[0] = nums[deque.peekFirst()];
            for (int i=k; i < n; i++) {
                while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                    deque.pollLast();
                }
                deque.offerLast(i);
                while (deque.peekFirst() <= i -k) {
                    deque.pollFirst();
                }
                ans[i - k + 1] = nums[deque.peekFirst()];
            }
            return ans;
        }
    }
    
    func maxSlidingWindow(nums []int, k int) []int {
        // Go 方法二:单调队列
        q := []int{}
        push := func(i int) {
            for len(q) > 0 && nums[i] >= nums[q[len(q) -1]] {
                q = q[:len(q)-1]
            }
            q = append(q,i)
        }
    
        for i := 0; i < k; i++ {
            push(i)
        }
    
        n := len(nums)
        ans := make([]int,1,n-k+1)
        ans[0] = nums[q[0]]
        for i := k; i < n; i++ {
            push(i)
            for q[0] <= i-k {
                q = q[1:]
                }
                ans = append(ans, nums[q[0]])
        }
        return ans
    }
    

    方法三:分块 + 预处理

    class Solution {
        // Java 方法三:分块 + 预处理 —— 最速解
        public int[] maxSlidingWindow(int[] nums, int k) {
            int n = nums.length;
            int[] prefixMax = new int[n];
            int[] suffixMax = new int[n];
            for (int i = 0; i < n; i++) {
                if (i % k == 0) {
                    prefixMax[i] = nums[i];
                }else {
                    prefixMax[i] = Math.max(prefixMax[i-1],nums[i]);
                }
            }
            for (int i = n-1; i >= 0; i--) {
                if (i == n-1 || (i+1)%k == 0) {
                    suffixMax[i] = nums[i];
                }else{
                    suffixMax[i] = Math.max(suffixMax[i + 1],nums[i]);
                }
            }
            int[] ans = new int [n - k + 1];
            for (int i = 0; i <= n -k; ++i) {
                ans[i] = Math.max(suffixMax[i], prefixMax[i + k -1]);
            }
            return ans;
        }
    }
    
    func maxSlidingWindow(nums []int, k int) []int {
        // Go 方法三:分块 + 预处理
        n := len(nums)
        prefixMax := make([]int, n)
        suffixMax := make([]int, n)
        for i, v := range nums {
            if i % k == 0 {
                prefixMax[i] = v
            }else {
                prefixMax[i] = max(prefixMax[i-1], v)
            }
        }
        for i := n - 1; i >=0; i-- {
            if i == n-1 || (i+1)%k == 0 {
                suffixMax[i] = nums[i]
            } else {
                suffixMax[i] = max(suffixMax[i+1], nums[i])
            }
        }
    
        ans := make([]int, n-k+1)
        for i := range ans {
            ans[i] = max(suffixMax[i],prefixMax[i+k-1])
        }
        return ans
    }
    
    func max(a,b int) int {
        if a > b {
            return a
        }
        return b
    }
    

    641. 设计循环双端队列

    难度中等98

    设计实现双端队列。
    你的实现需要支持以下操作:

    • MyCircularDeque(k):构造函数,双端队列的大小为k。
    • insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。
    • insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。
    • deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。
    • deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。
    • getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。
    • getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。
    • isEmpty():检查双端队列是否为空。
    • isFull():检查双端队列是否满了。

    示例:

    MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3
    circularDeque.insertLast(1);			        // 返回 true
    circularDeque.insertLast(2);			        // 返回 true
    circularDeque.insertFront(3);			        // 返回 true
    circularDeque.insertFront(4);			        // 已经满了,返回 false
    circularDeque.getRear();  				// 返回 2
    circularDeque.isFull();				        // 返回 true
    circularDeque.deleteLast();			        // 返回 true
    circularDeque.insertFront(4);			        // 返回 true
    circularDeque.getFront();				// 返回 4
     
    

    提示:

    • 所有值的范围为 [1, 1000]
    • 操作次数的范围为 [1, 1000]
    • 请不要使用内置的双端队列库。
    // Java 双向链表实现,一个节点包含前后两个指针
    class MyCircularDeque {
        int capacity;
        int curContain = 0;
    
        class ListNode {
            int val;
            ListNode next;
            ListNode prev;
    
            public ListNode(int val) {
                this.val = val;
            }
        }
    
        ListNode start;
        ListNode end;
    
        public MyCircularDeque(int k) {
            this.capacity = k;
            start = new ListNode(0);
            end = start;
        }
        
        public boolean insertFront(int value) {
            if (isFull()) {
                return false;
            }
            ListNode newNode = new ListNode(value);
            newNode.next = start.next;
            if (newNode.next != null) {
                newNode.next.prev = newNode;
            }else{
                end = newNode;
            }
            newNode.prev = start;
            start.next = newNode;
            curContain += 1;
            return true;
        }
        
        public boolean insertLast(int value) {
            if (isFull()) {
                return false;
            }
            ListNode newNode = new ListNode(value);
            end.next = newNode;
            newNode.prev = end;
            end = end.next;
            curContain += 1;
            return true;
        }
        
        public boolean deleteFront() {
            if (isEmpty()) {
                return false;
            }
            ListNode nextNode = start.next.next;
            start.next.next = null;
            start.next.prev = null;
            start.next = nextNode;
            if (start.next != null) {
                start.next.prev = start;
            }else{
                end = start;
            }
            curContain -= 1;
            return true;
        }
        
        public boolean deleteLast() {
            if (isEmpty()) {
                return false;
            }
            ListNode preNode = end.prev;
            end.prev = null;
            preNode.next = null;
            end = preNode;
            curContain -= 1;
            return true;
        }
        
        public int getFront() {
            if (isEmpty()) {
                return -1;
            }
            return start.next.val;
        }
        
        public int getRear() {
            if (isEmpty()) {
                return -1;
            }
            return end.val;
        }
        
        public boolean isEmpty() {
            return start == end;
        }
        
        public boolean isFull() {
            return capacity == curContain;
        }
    }
    
    /**
     * Your MyCircularDeque object will be instantiated and called as such:
     * MyCircularDeque obj = new MyCircularDeque(k);
     * boolean param_1 = obj.insertFront(value);
     * boolean param_2 = obj.insertLast(value);
     * boolean param_3 = obj.deleteFront();
     * boolean param_4 = obj.deleteLast();
     * int param_5 = obj.getFront();
     * int param_6 = obj.getRear();
     * boolean param_7 = obj.isEmpty();
     * boolean param_8 = obj.isFull();
     */
    
    // Java 数组实现
    class MyCircularDeque {
        int size = 0;
        int tail = -1;
        int[] queue;
    
        public MyCircularDeque(int k) {
            size = k;
            queue = new int[k];
        }
        
        public boolean insertFront(int value) {
            if (isFull()) {
                return false;
            }
            for (int i = tail; i >= 0; i--) {
                queue[i + 1] = queue[i];
            }
            queue[0] = value;
            tail++;
            return true;
        }
        
        public boolean insertLast(int value) {
            if (isFull()) {
                return false;
            }
            tail++;
            queue[tail] = value;
            return true;
        }
        
        public boolean deleteFront() {
            if (isEmpty()) {
                return false;
            }
            for (int i=1; i <= tail; i++) {
                queue[i-1] = queue[i];
            }
            queue[tail] = 0;
            tail--;
            return true;
        }
        
        public boolean deleteLast() {
            if (isEmpty()) {
                return false;
            }
            queue[tail] = 0;
            tail--;
            return true;
        }
        
        public int getFront() {
            if (isEmpty()) {
                return -1;
            }
            return queue[0];
        }
        
        public int getRear() {
            if (isEmpty()) {
                return -1;
            }
            return queue[tail];
        }
        
        public boolean isEmpty() {
            return tail == -1;
        }
        
        public boolean isFull() {
            return tail == (size - 1);
        }
    }
    
    /**
     * Your MyCircularDeque object will be instantiated and called as such:
     * MyCircularDeque obj = new MyCircularDeque(k);
     * boolean param_1 = obj.insertFront(value);
     * boolean param_2 = obj.insertLast(value);
     * boolean param_3 = obj.deleteFront();
     * boolean param_4 = obj.deleteLast();
     * int param_5 = obj.getFront();
     * int param_6 = obj.getRear();
     * boolean param_7 = obj.isEmpty();
     * boolean param_8 = obj.isFull();
     */
    
    // Go 数组实现
    type MyCircularDeque struct {
        queue []int
        head int
        tail int
    }
    
    /** Initialize your data structure here. Set the size of the deque to be k. */
    func Constructor(k int) MyCircularDeque {
        return MyCircularDeque{
            queue: make([]int, k + 1),
            head: 0,
            tail: 0,
        }
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    func (this *MyCircularDeque) InsertFront(value int) bool {
        if this.IsFull(){
            return false
        }
        this.head = (this.head - 1 + len(this.queue)) % len(this.queue)
        this.queue[this.head] = value
        return true
    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    func (this *MyCircularDeque) InsertLast(value int) bool {
        if this.IsFull() {
            return false
        }
        this.queue[this.tail] = value
        this.tail = (this.tail + 1) % len(this.queue)
        return true
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    func (this *MyCircularDeque) DeleteFront() bool {
        if this.IsEmpty() {
            return false
        }
        this.head = (this.head + 1) % len(this.queue)
        return true
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    func (this *MyCircularDeque) DeleteLast() bool {
        if this.IsEmpty() {
            return false
        }
        this.tail = (this.tail - 1 + len(this.queue)) % len(this.queue)
        return true
    }
    
    /** Get the front item from the deque. */
    func (this *MyCircularDeque) GetFront() int {
        if this.IsEmpty() {
            return -1
        }
        return this.queue[this.head]
    }
    
    /** Get the last item from the deque. */
    func (this *MyCircularDeque) GetRear() int {
        if this.IsEmpty() {
            return -1
        }
        n := (this.tail - 1 + len(this.queue)) % len(this.queue)
        return this.queue[n]
    }
    
    /** Checks whether the circular deque is empty or not. */
    func (this *MyCircularDeque) IsEmpty() bool {
        return this.head == this.tail
    }
    
    /** Checks whether the circular deque is full or not. */
    func (this *MyCircularDeque) IsFull() bool {
        return (this.tail + 1) % len(this.queue) == this.head
    }
    
    
    /**
     * Your MyCircularDeque object will be instantiated and called as such:
     * obj := Constructor(k);
     * param_1 := obj.InsertFront(value);
     * param_2 := obj.InsertLast(value);
     * param_3 := obj.DeleteFront();
     * param_4 := obj.DeleteLast();
     * param_5 := obj.GetFront();
     * param_6 := obj.GetRear();
     * param_7 := obj.IsEmpty();
     * param_8 := obj.IsFull();
     */
    

    42. 接雨水

    难度困难2756

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

    示例 1:

    img

    输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
    输出:6
    解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 
    

    示例 2:

    输入:height = [4,2,0,3,2,5]
    输出:9
    

    提示:

    • n == height.length
    • 1 <= n <= 2 * 104
    • 0 <= height[i] <= 105
    class Solution {
        // Java 方法 1:暴力
        public int trap(int[] height) {
            int ans = 0;
            int size = height.length;
            for (int i = 1; i < size - 1; i++) {
                int max_left = 0; 
                int max_right = 0;
                for (int j = i; j >=0 ; j--) {
                    max_left = Math.max(max_left,height[j]);
                }
                for (int j = i; j < size; j++) {
                    max_right = Math.max(max_right, height[j]);
                }
                ans += Math.min(max_left,max_right) - height[i];
            }
            return ans;
        }
    }
    
    // G 方法 1:暴力
    func trap(height []int) int {
        ans := 0
        size := len(height)
        for i := 1; i < size; i++ {
            max_left := 0
            max_right := 0
            for j := i; j >= 0; j-- {
                max_left = max(max_left,height[j])
            }
            for j := i ; j < size ; j++ {
                max_right = max(max_right,height[j])
            }
            ans += min(max_left,max_right) - height[i]
        }
        return ans
    }
    func max(x, y int) int {
        if x > y {
            return x
        }
        return y
    }
    func min(x, y int) int {
        if x < y {
            return x
        }
        return y
    }
    

    方法二:单调栈

    class Solution {
        // Java 方法二:单调栈
        public int trap(int[] height) {
            int ans = 0;
            Deque<Integer> stack = new LinkedList<Integer>();
            int n = height.length;
            for (int i = 0; i < n; i++) {
                while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                    int top = stack.pop();
                    if (stack.isEmpty()) {
                        break;
                    }
                    int left = stack.peek();
                    int currWidth = i - left - 1;
                    int currHeight = Math.min(height[left], height[i]) - height[top];
                    ans += currWidth * currHeight;
                }
                stack.push(i);
            }
            return ans;
        }
    }
    
    // Go 方法二:单调栈 
    // 指明返回的是ans 就可以直接return 不用带参数
    func trap(height []int) (ans int) {
        stack := []int{}
        for i, h := range height {
            for len(stack) > 0 && h > height[stack[len(stack) - 1]] {
                top := stack[len(stack) - 1]
                stack = stack[:len(stack) - 1]
                if len(stack) == 0 {
                    break
                }
                left := stack[len(stack) - 1]
                curWidth := i - left -1
                curHeight := min(height[left],h) - height[top]
                ans += curWidth * curHeight
            }
            stack = append(stack,i)
        }
        return
    }
    
    func min(x, y int) int {
        if x < y {
            return x
        }
        return y
    }
    
    class Solution {
        // Java 方法三:双指针
        public int trap(int[] height) {
            int ans = 0;
            int left = 0;
            int right = height.length - 1;
            int leftMax = 0;
            int rightMax = 0;
            while (left < right) {
                leftMax = Math.max(leftMax, height[left]);
                rightMax = Math.max(rightMax, height[right]);
                if (height[left] < height[right]) {
                    ans += leftMax - height[left];
                    left ++;
                } else {
                    ans += rightMax - height[right];
                    right --;
                }
            }
            return ans;
        }
    }
    
    // Go 方法三:双指针
    // 声明返回的是ans 就可以直接return 不用带参数
    func trap(height []int) (ans int) {
        left := 0
        right := len(height) -1
        leftMax := 0
        rightMax := 0
        for left < right {
            leftMax = max(leftMax,height[left])
            rightMax = max(rightMax,height[right])
            if (height[left] < height[right]) {
                ans += leftMax - height[left]
                left++
            } else {
                ans += rightMax - height[right]
                right--
            }
        }
        return
    }
    
    func max(x, y int) int {
        if x > y {
            return x
        }
        return y
    }
    
  • 相关阅读:
    使用Graphics合成带二维码和头像的分享图(小程序分享、App分享)
    04_关键字的作用
    03_线程
    02_进程
    01_命名规范
    WebApi的创建,部署,Oauth身份认证(三)
    WebApi的创建,部署,Oauth身份认证(二)
    WebApi的创建,部署,Oauth身份认证(一)
    Prism.Interactivity 和 Prism.Modularity 介绍
    Prism BindableBase 和 Commands 的介绍
  • 原文地址:https://www.cnblogs.com/OwlInTheOaktree/p/15398773.html
Copyright © 2011-2022 走看看