|
给定一个整数组和一个整数 k, 从所有大小K在 的连续子数组中找 的最大元素。
, r; V8 c. E9 M0 T9 `$ r* E; a例如:
( y: K: [2 e; W, G8 ^Input : int[] arr = {2,6,-1,2,4,1,-6,5}int k = 3output 每个大小都是 k 子数组,打印其最大元素。
, D4 f* ^7 |+ G# u! M/ } 2 E* G; B, Q# l/ J- z9 c
解决方案:
1 l4 L1 q, y0 s 生成所有大小的基本解决方案k为了找出当前子数组的最大值,连续子数组并循环遍历它们。考虑到每一点,我们基本上都取下一个 ''k 元素,然后我们经历了 k 元素,所以算法的最坏时间复杂度将是O(n*k)。
i1 f1 k; Z+ C( Mpackage Arrays;import java.util.Scanner;public class slidingWindowMax public static void main(String[] args) Scanner scn = new Scanner(System.in); int [] arr = new int[scn.nextInt();for(int i = 0; i ( w7 Q$ Y8 s0 h" ?
通过使用Segment 树,我们当然可以减少为每个子数组找到最大值的时间。
2 X2 J" S' B) W我们可以为给定的数组实现一个段树,我们可以通过范围查询[i,i k-1]获得每个子数组的最大值。
# p" n E, q; E6 U S段树节点总数:" r/ x# f5 f$ |, y! Z1 n
建段树最坏的时间复杂度是O(n),因为我们知道,4 H! g8 N" \- b
(i) 段树的叶节点包含数组的所有元素。) P: F; P& C! Y& I6 j6 v
(ii) 最后一层的节点数是所有上一层的节点数。! O `/ A$ a& R5 y: i( H4 b6 a/ ?
在数学上,
c) n" m$ r+ o: f# K2 x7 a9 `- {- K考虑数组长度为 n,因此,线段树的叶节点将是 n。
, D1 Z4 b2 u2 T7 q9 o; w因此,所有上层节点都将是 n-1。
( n" G9 X2 }7 k" ^9 [长度为 n 段树上数组的总节点为:( u/ U! A; S2 u4 r5 R$ S
Tn = leaf nodes nodes on upper levels = n n- = 2n 1复杂性分析
0 g; v2 j* L& L* r; K我们的线段树的建设只涉及每个节点的计算,所以线段树的最坏时间复杂度将是 O(2n 1) 即O(n)。5 b5 Q; ]6 |9 @7 a, P% I
在每个子数组范围内查询结果O(logk) 中计算。
0 ~5 ^: E8 [2 x将所有大小为 k 的“n-k 1个子数组查询计算。+ d! d6 R# P) U5 |
因此,该算法的整体时间复杂度为 O((n-k 1)*logk) 即O(nlogk)。" Y9 _8 [2 g; T6 A! L: ?
package Arrays;import java.util.Scanner;public class slidingWindowMax static int[] sarr; public static void main(String[] args) Scanner scn = new Scanner(System.in); int[] arr = new int[scn.nextInt();for (int i = 0; i QueryEnd || end = queryStart && end 最有效的方法:; X X+ ~* a) ]% q
我们使用这种方法Deque帮助我们找到它O(n) 滑动窗最大值。
$ i+ e2 P0 \% Q/ Z9 ] \" DDeque它基本上是一个队列,两个排队deque,即,可以添加或删除元素或者从前面或后面的端部开放。
3 S4 C) P; m% G解决问题的实际方法是:
0 u" ~, X9 a8 g' `# G, I5 l+ X我们以相反的顺序保留子数组的 k 个元素,我们不需要保留所有 k 元素,虽然我们以后会在代码中看到。) J; w% e( [ N0 X9 h+ v1 U, @, N! {
为前 k 个元素生成 Deque,保持它们以相反的顺序排序,使最大元素位于前面。
( \. a& }0 ]7 Y$ f4 F; b如果 Deque 为空,直接添加元素,否则检查输入元素是否大于最后一个元素,如果是,继续从最后一个元素弹出到剩余 Deque 的最后一个元素大于传入元素。
) u: Y( F1 l$ g) e/ h属于不同子数组的元素同子数组的元素。Deque 索引必须在[i,i k]范围内。4 b8 {- Y7 |& [) N0 l# m( ?
两种情况下只删除一个元素:4 m2 y0 [$ V# h( e
(i)如果即将到来的元素大于后 元素,如果是,它将继续弹出元素,直到更大的元素出现在剩的元素,因为我们需要保持数组以相反的顺序排序。
! d+ [& a2 }$ |; M; M6 L$ ?(ii) 如果元素属于任何其他子数组,则保留它没有意义。
. B$ ?) f F% k7 G& spackage org.arpit.java2blog;import java.util.LinkedList;import java.util.Scanner;public class SlidingWindowMax static int[] sarr; public static void main(String[] args) Scanner scn = new Scanner(System.in); int[] arr = new int[scn.nextInt();for (int i = 0; i ();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;for (int i = 0; i = k-1) { /* only print when we have processed atleast k elements * to make the very first subarray */ System.out.print(" " arr[deque.getFirst()]); } } }}当您操作上述程序时,您将获得以下输出:
, e$ _* E* k, G, P8 q5 N; w/ S82 6 -1 2 4 1 -6 5arr[]-1 2 4 1 -6 5 }36 4 4 4 4 5 5 |
|