我一直在寻找一个着名的问题,即: 在给定的数组上,我们尝试以相同的大小构建另一个数组, 其中新数组中的每个元素将是原始数组(连续)中左侧较小元素的数量。我一直在StackOverflow中搜索,我只在O(nlogn)中找到了解决方案。我想我已经在O(n)找到了解决方案。
int[] arr = {8, 4, 3, 2, 10, 9, 7, 6, 12};
Stack<Integer> stack = new Stack<>();
int[] newArr = new int[arr.length];
// Each sequence is at least 1;
for (int i = 0; i < newArr.length; i++) {
newArr[i] = 1;
}
// For each element, if it is smaller than
// the previous one, push it into the stack.
// Otherwise, compare it to all the elements
// in the stack which are smaller or equals to it,
// and summarize their values in the newArr.
stack.push(arr[0]);
for (int i = 1; i < arr.length; i++) {
if (arr[i] >= arr[i-1]) {
int j = i - 1;
while (!stack.isEmpty() && stack.top() <= arr[i]) {
arr[i] += newArr[j];
stack.pop();
j--;
}
}
stack.push(arr[i);
}
现在,复杂性时间是O(n),因为任何值只比较一次, 在最坏的情况下,有'n'个数字,并且它们被分成 'k'下降组(例如{18,12,11,9,17,8,6,4,15,3,2,1}),我们是 对于'n / k'元素,仅激活第二个循环'k'次。这就是为什么 'k'变量并不重要,在最坏的情况下我们留下O(n)。
*我忘了提及,代码中的newArr应如下所示: {1,1,1,1,5,1,1,1,9} *
如果我是对的,请告诉我,这对我来说非常重要。 此致 尤赖亚。
答案 0 :(得分:1)
是的,你的论点绝对正确。代码的时间复杂度为O(n)。
事实上,每个数字都可以从堆栈中添加和弹出一次,这也很容易证明。从而使其成为O(n)。
执行相同任务的备用算法(更直观):
// push index instead of number itself
stack.push(0);
for (int i = 1; i < arr.length; i++) {
while (!stack.isEmpty() && arr[stack.top()] <= arr[i])
stack.pop();
if(stack.isEmpty())
new_arr[i]=i+1;
else
new_arr[i]=i-stack.top()
stack.push(i);
}
正如您所注意到的,我推送索引而不是数字。这使得新数组的计算变得直观(只计算两个索引之间的差异)。