给定一个未排序的数组S和一个整数k,找出所有满足区间S[i...j]的范围(即max(S[i...j]) - min(S[i...j]))小于k的(i,j)配对数量。
我在面试中遇到了这个问题,只能想到在对S进行排序后得到O(nlogn)时间复杂度的解法。但是我被告知有一个O(n)的解法。你们有什么想法吗?
给定一个未排序的数组S和一个整数k,找出所有满足区间S[i...j]的范围(即max(S[i...j]) - min(S[i...j]))小于k的(i,j)配对数量。
我在面试中遇到了这个问题,只能想到在对S进行排序后得到O(nlogn)时间复杂度的解法。但是我被告知有一个O(n)的解法。你们有什么想法吗?
S = [1,3,-1,2,5,3,6,2,4,0]
k = 5
首先:
i S[p] start min max pairs
0 1 0 1 1 -
1 3 0 1 3 1
2 -1 0 -1 3 2
3 2 0 -1 3 3
4 5
在这一点上,我们得到了一个大于min+k的值。因此,我们将当前值S[i]设置为新的最小值和最大值,并向后迭代(同时更新最小值),直到找到第一个小于或等于max-k的值,即S[2]=-1;因此,S[3]成为新的最小值,3成为新的起始索引:
i S[p] start min max pairs
4 5 3 2 5 1
5 3 3 2 5 2
6 6 3 2 6 3
7 2 3 2 6 4
8 4 3 2 6 5
9 0
在这一点上,我们得到了一个小于或等于max-k的值。因此,我们将min和max设置为0,并向后迭代(同时更新max),直到达到大于或等于min+k的S[6],因此7成为新的起始索引;请注意,新的最大值不是S[start],而是我们在路上传递的更高值4。
i S[p] start min max pairs
9 0 7 0 4 2
总共的配对数是23(如果我正确理解了它们的计算方式)。
如果你想把复杂度降低到O(n),有很多选择,但Stefan Haustein的答案可能是最好的选择。
import java.util.LinkedList;
public class Ranges {
public static int countRanges(int[] s, int k) {
int i = 0;
int min = s[0];
int max = s[0];
LinkedList<Integer> ascending = new LinkedList();
ascending.add(0);
LinkedList<Integer> descending = new LinkedList();
descending.add(0);
System.out.println("[0...0]");
int count = 1;
for (int j = 1; j < s.length; j++) {
int value = s[j];
while (!ascending.isEmpty() && s[ascending.getLast()] > value) {
ascending.removeLast();
}
ascending.add(j);
while (!descending.isEmpty() && s[descending.getLast()] < value) {
descending.removeLast();
}
descending.add(j);
if (s[j] > max) {
max = s[j];
if (max - min >= k) {
while(max - s[ascending.getFirst()] >= k) {
ascending.removeFirst();
}
i = ascending.getFirst();
min = s[i];
while (descending.getFirst() < i) {
descending.removeFirst();
}
}
} else if (s[j] < min) {
min = s[j];
if (max - min >= k) {
while(s[descending.getFirst()] - min >= k) {
descending.removeFirst();
}
i = descending.getFirst();
max = s[i];
while (ascending.getFirst() < i) {
ascending.removeFirst();
}
}
}
System.out.println("[" + i + "..." + j + "]");
count += j - i + 1; // New subarrays involving j
}
return count;
}
public static void main(String[] args) {
final int[] s = new int[] {1, 7, 2, 3, 4, 1, 2, 5, 6};
final int k = 3;
System.out.println("count: " + countRanges(s, k));
}
}
工作笔记:https://i.imgur.com/G2FlSoc.jpg O:)
(注:本段内容为原文,无需翻译)unsigned long countPairs(vector<int>& nums, int limit) { //Number of sub-arrays with range less than or equal to k
limit--; //Number of sub-arrays with range less than k
deque<int>minDeque,maxDeque;
int start=0;
unsigned long ans=0;
for(int end =0;end<nums.size();++end){
int w = nums[end];
while(!minDeque.empty() && nums[minDeque.back()]>w) minDeque.pop_back();
minDeque.push_back(end);
while(!maxDeque.empty() && nums[maxDeque.back()]<w) maxDeque.pop_back();
maxDeque.push_back(end);
if(!maxDeque.empty() and !minDeque.empty()) {
while (nums[maxDeque.front()] - nums[minDeque.front()] > limit) {
if (!maxDeque.empty() and nums[maxDeque.front()] == nums[start]) maxDeque.pop_front();
if (!minDeque.empty() and nums[minDeque.front()] == nums[start]) minDeque.pop_front();
start++;
}
ans += end - start + 1;
}
}
return ans;
}