在一个未排序的数组中,我们需要用其右侧第一个比当前元素大的元素替换每个元素。如果右侧没有比该元素大的元素,则应将其替换为-1
。
示例:
3 1 2 5 9 4 8 should be converted to
5 2 5 9 -1 8 -1
我可以想到一个平凡的解决方案,即检查每个元素与整个数组,这是一个Ο(n²)的解决方案。有更好的方法吗?
在一个未排序的数组中,我们需要用其右侧第一个比当前元素大的元素替换每个元素。如果右侧没有比该元素大的元素,则应将其替换为-1
。
示例:
3 1 2 5 9 4 8 should be converted to
5 2 5 9 -1 8 -1
我可以想到一个平凡的解决方案,即检查每个元素与整个数组,这是一个Ο(n²)的解决方案。有更好的方法吗?
主要思路是按照倒序(从右到左)处理数组。我们做出一些观察:
A[k] ≤ A[j]
,那么我们将称元素k为无关元素,因为它永远不会成为任何1,2,...,k元素的结果。A[i+1..n-1]
的单调递增子序列。在您的示例中,相关元素的序列从右到左:
[]
[8]
[4,8]
[9]
[5,9]
[2,5,9]
[1,5,9]
看起来像是一个栈,实际上我们可以使用栈在迭代之间维护这个序列。
处理新元素时,我们首先需要找到数组元素的结果。观察结果是栈顶上未被新元素使无效的最高元素。因此,我们只需从栈中弹出所有变得无关紧要的元素。然后,我们的结果就在栈顶。接下来,我们可以将新元素推入栈中,因为按照我们的定义它是相关的。
stack = []
A = [3, 1, 2, 5, 9, 4, 8]
result = [-1]*len(A)
for i := len(A) - 1 to 0:
# remove all elements made irrelevant by A[i]
while not stack.empty() && stack.top() <= A[i]:
stack.pop()
# now the top of the stack is the result for index i
if not stack.empty():
R[i] = stack.top()
# push the new element on the stack. The stack will still contain all relevant
# elements in increasing order from top to bottom
stack.push(A[i])
迭代i
的循环不变条件是"stack
包含索引i
右侧相关元素的子序列"。 它易于验证并暗示了此算法的正确性。A[k] ≤ A[j]
。此外,如果你将 if
和 while
的主体放在自己的一行上,你的代码会更易读。除了细节之外:+1 - Walter TrossO(n)
)。 - Niklas B.你可以使用栈,时间复杂度为O(N)
。
算法:
从左侧开始向右移动。当你选择一个数组元素(假设为x)时,弹出栈直到栈中的元素(假设为y)有大于数组元素即x>y的元素。然后将该元素即x推入栈中。
例如:{40,50,11,32,55,68,75}
。这里s
是栈。
40,因为s为空,所以将其推入。 s: 40
50,因为s.peek() < 50,所以弹出40(40的更大元素是50),然后推入50。 s: 50
40的下一个更大元素是50。
11,s.peek() > 11,所以推入11。 s: 50, 11
32,s.peek() < 32,所以弹出元素,现在是50,它比32大,因此推入32。 s: 50, 32
11的下一个更大元素是32。
55,s.peek() < 55,所以弹出元素,即32,然后弹出50 < 55,然后推入55。 s: 55
。
32的下一个更大元素是55。
50的下一个更大元素是55。
68,s.peek() < 68,所以弹出并推入68。 s: 68
75,s.peek() < 75,所以弹出并推入75 s:75
。
68的下一个更大元素是75。
由于数组没有任何元素,只需弹出栈即可,表示所有数组中的元素都没有更大的元素,即-1。
75的下一个更大元素是-1。
相同算法的代码:
public static void fun(int[] a) {
Stack<Integer> s = new Stack<Integer>();
s.push(a[0]);
for (int i = 1; i < a.length; i++) {
if (s.peek() != null) {
while (true) {
if (s.peek() == null || s.peek() > a[i]) {
break;
}
System.out.println(s.pop() + ":" + a[i]);
}
}
s.push(a[i]);
}
while (s.peek() != null) {
System.out.println(s.pop() + ":" + -1);
}
}
O(n)
的时间复杂度内运行。但是你的实现是错误的。 - Niklas B.