LeetCode上的一个名为3Sum Smaller的问题是:
给定一组
n
整数nums
和target
,找到满足条件{{1}的i, j, k
索引三元组0 <= i < j < k < n
的数量}}你能在O(n ^ 2)运行时解决它吗?
常见的O(n ^ 2)solution people agree upon是:
nums[i] + nums[j] + nums[k] < target
我不明白这是怎么回事O(n ^ 2)。当然,该算法使用了一些方便的快捷方式来节省时间(主要是通过排序和使用我们的优势),但我不知道它是如何确保O(n ^ 2)。
是否有一些数学原因,这是O(n ^ 2)而不是O(n ^ 3),如果是这样,请你解释一下它背后的原理,以便我能发现这种行为再次?
答案 0 :(得分:1)
确定这一点的一种非常简单的方法是n ^ 2算法正在查看循环。
外(for)循环最多迭代n次(技术上是n-2但无论如何)。内循环取决于左和右的值。
left是在LEAST 1,右边是MOST len = n(技术上是len-1但是无论如何)内部循环仅在left < right
时执行,所以在最坏的情况下内部循环在MOST迭代n次。
外循环最多迭代n次。对于外循环的每次迭代,内循环最多迭代n次。算法是O(n ^ 2)。此算法也是O(n ^ 3),因为O(n ^ 2)= O(n ^ 3)。
另一个不在恒定时间内运行的语句是:
Arrays.sort(nums);
假设有效的排序算法,此操作在O(nlog n)中运行,该操作在O(n ^ 2)中,因此它不会影响最终的时间复杂度。
进行时间复杂度分析时的一个技巧。忘记算法应该做什么,只查看循环以及它们可能运行的程度。
答案 1 :(得分:1)
public class Solution {
int count; //constant operation
public int threeSumSmaller(int[] nums, int target) {
count = 0; //constant operation
Arrays.sort(nums); //sorting is generally considered O(nlogn)
int len = nums.length; //constant operation
for(int i=0; i<len-2; i++) { //O(n) operation
int left = i+1, right = len-1; //two constant operations
while(left < right) { //O(n) operation
if(nums[i] + nums[left] + nums[right] < target) { //constant operation
count += right-left; //constant operation
left++; //constant operation
} else {
right--; //constant operation
}
}
}
return count; //constant operation
}
}
上面我已经用每行的基本运行时间注释掉了你的代码块。如您所见,有两个O(n)操作和一个O(nlogn)操作。通常假设排序为O(nlogn)。您的功能每次调用都会执行一次此操作。 O(n)操作是嵌套的,因此对于前N个操作,它执行N个后续操作。这是O(n ^ 2)。你的程序是O(nlogn)+ O(n ^ 2),这使得总数为O(n ^ 2),因为只有最高阶项很重要。