我正在尝试从CodeFights解决下面的问题。在问题之后我把答案留给了Java。该代码适用于所有问题,除了最后一个。报告时间限制异常。我该怎么做才能让它低于3000毫秒(CodeFights要求)?
注意:编写具有O(n)时间复杂度和O(1)额外空间复杂度的解决方案,因为这是您在真实访谈期间要求做的事情。
给定一个仅包含1到a.length范围内的数字的数组a,找到第二个匹配项具有最小索引的第一个重复数字。换句话说,如果有多于1个重复的数字,则返回第二次出现的索引小于另一个出现的第二次出现的索引的数量。如果没有这样的元素,则返回-1。
实施例
对于a = [2,3,3,1,5,2],输出应为 firstDuplicate(a)= 3.
有两个重复:数字2和3.第二次出现的3的索引小于第二次出现的2,所以答案是3。
对于a = [2,4,3,5,1],输出应为 firstDuplicate(a)= -1。
输入/输出
[时间限制] 3000ms(java) [input] array.integer a
保证约束: 1≤a.length≤105, 1≤a[i]≤a.length。
[输出]整数
a中的元素不止一次出现在数组中,并且第二次出现的索引最小。如果没有这样的元素,则返回-1。
int storedLeastValue = -1;
int indexDistances = Integer.MAX_VALUE;
int indexPosition = Integer.MAX_VALUE;
for (int i = 0; i < a.length; i++)
{
int tempValue = a[i];
for (int j = i+1; j < a.length; j++) {
if(tempValue == a[j])
{
if(Math.abs(i-j) < indexDistances &&
j < indexPosition)
{
storedLeastValue = tempValue;
indexDistances = Math.abs(i-j);
indexPosition = j;
break;
}
}
}
}
return storedLeastValue;
答案 0 :(得分:3)
您的解决方案有两个嵌套的for循环,这意味着O(n ^ 2),而问题明确要求O(n)。由于您还有空间限制,因此您无法使用额外的Set(也可以提供简单的解决方案)。
这个问题适用于具有强大算法/图论背景的人。解决方案很复杂,包括在有向图中找到循环的入口点。如果您不熟悉这些条款,我建议您将其留下并转移到其他问题。
答案 1 :(得分:0)
这个怎么样:
public static void main(String args[]) {
int [] a = new int[] {2, 3, 3, 1, 5, 2};
// Each element of cntarray will hold the number of occurrences of each potential number in the input (cntarray[n] = occurrences of n)
// Default initialization to zero's
int [] cntarray = new int[a.length + 1]; // need +1 in order to prevent index out of bounds errors, cntarray[0] is just an empty element
int min = -1;
for (int i=0;i < a.length ;i++) {
if (cntarray[a[i]] == 0) {
cntarray[a[i]]++;
} else {
min = a[i];
// no need to go further
break;
}
}
System.out.println(min);
}
答案 2 :(得分:0)
这个练习的好答案可以在这里找到 - https://forum.thecoders.org/t/an-interesting-coding-problem-in-codefights/163 - 一切都是就地完成的,它有O(1)解决方案。
答案 3 :(得分:0)
选中它,它也是O(n),但没有其他数组。
int firstDuplicate(int[] a) {
if (a.length <= 1) return -1;
for (int i = 0; i < a.length; i++) {
int pos = Math.abs(a[i]) - 1;
if (a[pos] < 0) return pos + 1;
else a[pos] = -a[pos];
}
return -1;
}
答案 4 :(得分:0)
接受的答案不适用于该任务。 如果输入数组确实包含的值不超过其长度,则它将起作用。 但是确实如此,例如:[5,5]。
因此,我们必须定义最大的数字。
int firstDuplicate(int[] a) {
int size = 0;
for(int i = 0; i < a.length; i++) {
if(a[i] > size) {
size = a[i];
}
}
int[] t = new int[size+1];
for(int i = 0; i < a.length; i++) {
if(t[a[i]] == 0) {
t[a[i]]++;
} else {
return a[i];
}
}
return -1;
}
答案 5 :(得分:0)
您可以将数组值存储在hashSet中。检查hashSet中是否已经存在值(如果不存在),然后将其添加到hashSet中,否则将是您的答案。下面是通过所有测试用例的代码:-
int firstDuplicate(int[] a) {
HashSet<Integer> hashSet = new HashSet<>();
for(int i=0; i<a.length;i++){
if (! hashSet.contains(a[i])) {
hashSet.add(a[i]);
} else {
return a[i];
}
}
return -1;
}