左云 算法3

本文深入探讨了滑动窗口和单调栈两种数据结构在解决数组问题中的应用。首先,详细解释了如何使用双端队列实现滑动窗口,找到数组中的最大子数组。接着,通过单调栈展示了如何在无重复值和有重复值的数组中找出每个元素左侧和右侧的最近小于自身值的元素。最后,提到了利用单调栈求解无序数组中第K小的数的优化方法,包括对传统快速排序的改写。这些算法都体现了数据结构在高效解决问题中的关键作用。
摘要由CSDN通过智能技术生成

1.滑动窗口

双端队列:队列的头和尾都可以压入和弹出

在这里插入图片描述
在这里插入图片描述

	public static int[] getMaxWindow(int[] arr, int w) {
		if (arr == null || w < 1 || arr.length < w) {
			return null;
		}
		// qmax 窗口最大值的更新结构
		// qmax 中放数组的下标
		//linkedList可以当作双端队列
		LinkedList<Integer> qmax = new LinkedList<Integer>();
		//放找出的最大结果
		int[] res = new int[arr.length - w + 1];
		int index = 0;
		for (int R = 0; R < arr.length; R++) {
			//把双端队列中小于等于当前值从尾部弹出,并从尾部放入当前值
			while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[R]) {
				qmax.pollLast();
			}
			qmax.addLast(R);
			//从头部弹出双端队列中不在当前窗口中的值
			if (qmax.peekFirst() == R - w) {
				qmax.pollFirst();
			}
			//判断窗口的长度是否到达w
			if (R >= w - 1) {
				res[index++] = arr[qmax.peekFirst()];
			}
		}
		return res;
	}

2.单调栈

数组中无重复值

找出,数组中的一个值,左侧最靠近的比其小的值,其右侧离其最近的小于自己的值

栈中遵循小在下,大在上,入栈时,如果要入栈的值(2->2)比栈顶的值(1->4)小,再入栈就破坏了栈底小栈顶大的规则,要将栈顶(1->4)弹出,弹出的值(1->4)的右侧离其最近的小于自己的值就是,即将入栈的值(2->2),左侧最靠近的比其小的值就是其栈中压在下面的第一个值(0-3)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

	// arr = [ 3, 1, 2, 3]
	//         0  1  2  3
	//  [
	//     0 : [-1,  1]
	//     1 : [-1, -1]
	//     2 : [ 1, -1]
	//     3 : [ 2, -1]
	//  ]
	public static int[][] getNearLessNoRepeat(int[] arr) {
		//0位置放左测最近小与的值,1位置放右测最近小与的值
		int[][] res = new int[arr.length][2];
		// 只存位置!
		Stack<Integer> stack = new Stack<>();
		for (int i = 0; i < arr.length; i++) { // 当遍历到i位置的数,arr[i]
			//如果要入栈的值,比栈顶的值小,
			while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
				//再入栈就破坏了栈底小栈顶大的规则,要将栈顶弹出
				int j = stack.pop();
				//左侧最靠近的比其小的值就是其栈中压在下面的第一个值
				int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
				res[j][0] = leftLessIndex;
				//弹出的值的右侧离其最近的小于自己的值就是,即将入栈的值
				res[j][1] = i;
			}
			//如果要入栈的值,比栈顶的值大,入栈
			stack.push(i);
		}

		//最后算栈里剩的
		while (!stack.isEmpty()) {
			int j = stack.pop();
			int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
			res[j][0] = leftLessIndex;
			res[j][1] = -1;
		}
		return res;
	}

数组中有重复值

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


	public static int[][] getNearLess(int[] arr) {
		int[][] res = new int[arr.length][2];
		Stack<List<Integer>> stack = new Stack<>();
		for (int i = 0; i < arr.length; i++) { // i -> arr[i] 进栈
			while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
				//弹出的是一个链表,所以要计算链表中的每一个值
				List<Integer> popIs = stack.pop();
				//取出的下面链表中的最后一个位置的值
				int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
				//计算链表中的每一个值
				for (Integer popi : popIs) {
					res[popi][0] = leftLessIndex;
					res[popi][1] = i;
				}
			}
			如果要入栈的值,等于栈顶的链表中存放位置的值,放栈顶链表中
			if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
				stack.peek().add(Integer.valueOf(i));
			} else {
				//如果要入栈的值,比栈顶的值大,新建一个链表放入栈顶
				ArrayList<Integer> list = new ArrayList<>();
				list.add(i);
				stack.push(list);
			}
		}
		while (!stack.isEmpty()) {
			List<Integer> popIs = stack.pop();
			int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
			for (Integer popi : popIs) {
				res[popi][0] = leftLessIndex;
				res[popi][1] = -1;
			}
		}
		return res;
	}

利用单调栈

在这里插入图片描述
以数组中的一个位置为点,计算出,一位置上值为最小值的,最长的连续子数组,即找出左侧最靠近的比其小的值,其右侧离其最近的小于自己的值,中间的连续数组

暴力遍历

	public static int max1(int[] arr) {
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < arr.length; i++) {
			for (int j = i; j < arr.length; j++) {
				int minNum = Integer.MAX_VALUE;
				int sum = 0;
				for (int k = i; k <= j; k++) {
					sum += arr[k];
					minNum = Math.min(minNum, arr[k]);
				}
				max = Math.max(max, minNum * sum);
			}
		}
		return max;
	}

单调栈

3.无序数组中求第K小的数

在这里插入图片描述

改写快排

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值