问题:
给定N个整数A1,A2,.... AN,Dexter想知道他有多少种方法可以选择三个数字,这样他们就是算术级数的三个连续项。
这是我的解决方案(让“freq”成为计数器)
1. Create a data store (array of sorted sets) to hold a sorted set of positions of number i in stream at index i in array.
2. for k: 0 to array.length
a. get Sorted Set S[k]
b. if SZ >=3, where SZ = S[k].size, compute SZ choose 3 and add it to freq
c. for r: 2*k-1 to k
for x in S[k]
find entries in S[r], say A, more than x and entries in S[r-i], say B, less than x.. freq += A*B
find entries in S[r], say A, less than x and entries in S[r-i], say B, more than x.. freq += A*B
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
/**
*
* @author abhishek87
*/
class APTripletInStream {
public static void main(String[] args) {
int idx=0, numInStream;
Scanner scanIn = new Scanner(System.in), readLine;
String line = scanIn.nextLine();
readLine = new Scanner(line);
DataStore dStore = new DataStore(30000 + 1);
while(scanIn.hasNextLine()) {
line = scanIn.nextLine();
readLine = new Scanner(line);
while(readLine.hasNextInt()){
numInStream = readLine.nextInt();
dStore.add(++idx, numInStream);
}
break;
}
Long res = 0L;
try {
res = APProblemSolver.solveProblem(dStore);
} catch(Exception ex) {
res = 0L;
}
System.out.println(res);
}
}
class APProblemSolver {
public static Long solveProblem(DataStore dStore) {
Long freq = 0L;
int dSize = dStore.size();
for(int idx=1; idx<=dSize-1; idx++) {
Set currSet = dStore.getSetAtIndex(idx);
if(null != currSet && !currSet.isEmpty()) {
int size = currSet.size();
if(size >= 3) {
freq += (size*(long)(size-1)*(long)(size - 2)/6L);
}
for(int right = 2*idx-1; right > idx; right--){
if(right >= dSize)
continue;
Set rightSet = dStore.getSetAtIndex(right);
Set leftSet = dStore.getSetAtIndex(2*idx - right);
if(null != rightSet && null != leftSet) {
for(Object obj : currSet) {
Set leftSetHeadSet = ((TreeSet)leftSet).headSet(obj);
Set rightSetTailSet = ((TreeSet)rightSet).tailSet(obj);
freq += leftSetHeadSet.size() * rightSetTailSet.size();
Set leftSetTailSet = ((TreeSet)leftSet).tailSet(obj);
Set rightSetHeadSet = ((TreeSet)rightSet).headSet(obj);
freq += leftSetTailSet.size() * rightSetHeadSet.size();
}
}
}
}
}
return freq;
}
}
class DataStore {
private TreeSet[] list = null;
private int size;
public DataStore(int size) {
this.size = size;
list = new TreeSet[size];
}
public void add(Integer idx, Integer val) {
Set<Integer> i = list[val];
if(null == i) {
i = new TreeSet<Integer>();
i.add(idx);
list[val] = (TreeSet<Integer>)i;
} else{
((TreeSet<Integer>)list[val]).add(idx);
}
}
public int size() {
return size;
}
public Set getSetAtIndex(int idx) {
return list[idx];
}
}
以下是我要找的内容:
当我提交问题时,我得到“超出时间限制”。因此,我想使用NetBeans Profiler来估计此解决方案所需的时间,以便我可以改进它。 仅供参考 - 成功提交的时间限制为3秒
任何人都可以通过以下方式给我一些指导来改进我的解决方案[我不想改变我的解决方案]:
示例:
输入:
Number Of entries - 10.
Number Stream - 3 5 3 6 3 4 10 4 5 2.
输出:
9.
说明:
The followings are all 9 ways to choose a triplet:
(Ai, Aj, Ak) = (3, 3, 3)
(Ai, Aj, Ak) = (3, 4, 5)
(Ai, Aj, Ak) = (3, 4, 5)
(Ai, Aj, Ak) = (3, 4, 5)
(Ai, Aj, Ak) = (3, 4, 5)
(Ai, Aj, Ak) = (6, 4, 2)
(Ai, Aj, Ak) = (6, 4, 2)
(Ai, Aj, Ak) = (3, 4, 5)
(Ai, Aj, Ak) = (3, 4, 5)
答案 0 :(得分:1)
我没有详细检查你的代码,但这是我将如何做的:
Sort your list -- 1
Iterate through your sorted list (i from 0 to n) -- 2
Iterate though the remaining part of the list (j from i+1 to n) -- 2.a
Lookup if (2*j-i) which would be the third element of the arithmetic progression -- 2.a.1
步骤1是O(n * log(n))但是由于二进制搜索,它允许步骤2.a.1为O(log(n-j))。
这是我的python实现:
from bisect import bisect_left
def index_in_sorted(a, x):
'Locate the leftmost value exactly equal to x'
i = bisect_left(a, x)
if i != len(a) and a[i] == x:
return i
return None
numbers=[4,5,6,17,9,1,442,44,32,3,21,19]
print numbers
numbers.sort()
n = len(numbers)
for i in range(0,n):
n_i = numbers[i]
for j in range(i+1,n):
n_j = numbers[j]
n_k = 2*n_j - n_i
if index_in_sorted(numbers,n_k): # I could only process the end of numbers but it's not worth the pain
print "Found", n_i,n_j,n_k
答案 1 :(得分:1)
您应该实施数据存储区的lazy instantiation。
public DataStore(int size) {
for(int i=0; i<size;i++)
list.add(i, new TreeSet<Integer>());
}
在实例化期间创建30001个树集。
拥有所需内容的地图int -> Set
会好得多。然后在代码dStore.getSetAtIndex(right)
中,如果没有为此int设置,则实例化它。
明显的部分是:
for(Object objMore : leftSetTailSet) {
for(Object objLess : rightSetHeadSet) {
freq++;
}
}
可以更改为freq += leftSetTailSet*rightSetHeadSet;
此外,我没有看到dsStore大小发生变化:
而不是:{for}循环中的idx<=dStore.size()-1;
您可以声明变量dsSize = dStore.size()
并拥有idx < dsSize
和if(right >= dsSize)
答案 2 :(得分:1)
最重要的是,如果你有前两个学期,那么第三个学期是固定的。
利用记忆力你可以做得更好。
让我们有一个数组数组。我不知道你是如何用Java做的,这里是C ++版本。
vector<vector<int> > where
其中[i] =输入中的位置 value = i
所以{1,4,2,3,3}看起来像
where[0]={}
where[1]={0}
where[2]={2}
where[3]={3,4}
where[4]={1}
如果初始化上面的向量向量,那么将对位置进行排序。
再次,您可以设置AP的前2个元素,现在不是在原始输入流中搜索第三个元素,而是可以在 中轻松查找。
我总是结束算法问题:我们能做得更好吗?我确信有更好的方法,如果我点击它,我会更新这个答案。