Java 如何在O(logn)时间复杂度下解决这个问题
问题陈述:给定已排序的整数数组,从给定数组中查找非重复整数。数组中只有1个非重复整数,另一个整数范围为2 输入:[1,1,2,2,4,5,5] 产出:4 输入:[10,10,12,12,15,15,16,18,18] 产出:16 有谁能帮我解决这个时间复杂度为O(logn)的问题吗Java 如何在O(logn)时间复杂度下解决这个问题,java,arrays,data-structures,Java,Arrays,Data Structures,问题陈述:给定已排序的整数数组,从给定数组中查找非重复整数。数组中只有1个非重复整数,另一个整数范围为2 输入:[1,1,2,2,4,5,5] 产出:4 输入:[10,10,12,12,15,15,16,18,18] 产出:16 有谁能帮我解决这个时间复杂度为O(logn)的问题吗 注意:N是数组的长度更新 有人指出,原始代码将获取数组的切片,如果通过副本执行,则会使复杂性O(n)。下面是使用指向数组的指针的代码版本: 爪哇: Python: def singleton(arr, lo, hi)
注意:N是数组的长度更新 有人指出,原始代码将获取数组的切片,如果通过副本执行,则会使复杂性
O(n)
。下面是使用指向数组的指针的代码版本:
爪哇:
Python:
def singleton(arr, lo, hi):
if (hi == lo):
return arr[hi]
m = (hi + lo) // 2
if (m % 2 == 1):
if (arr[m] == arr[m-1]):
return singleton(arr, m+1, hi)
if (arr[m] != arr[m+1]):
return arr[m]
return singleton(arr, lo, m-1);
else:
if (arr[m] == arr[m+1]):
return singleton(arr, m+2, hi)
if (arr[m] != arr[m-1]):
return arr[m]
return singleton(arr, lo, m);
原始答案
因为您知道数组中的所有其他整数正好出现两次,所以可以进行二进制搜索以查找只出现一次的值。您需要查找数组的中点,并确定单例是发生在该数字之前、之后还是该数字。如果是在之前或之后,则继续搜索,但仅搜索数组的该部分(最多一半)。这是O(logn)
。在python中(注意:当我最初回答这个问题时,它没有标记为java
——我随后在下面添加了一个java解决方案),您可以将其实现为:
def singleton(arr):
m = len(arr) // 2
if (m == 0):
return arr[0]
if m % 2 == 1:
if arr[m] == arr[m-1]:
return singleton(arr[m+1:])
if arr[m] != arr[m+1]:
return arr[m]
return singleton(arr[:m])
else:
if arr[m] == arr[m+1]:
return singleton(arr[m+2:])
if arr[m] != arr[m-1]:
return arr[m]
return singleton(arr[:m+1])
示例用法:
print(singleton([1,1,2,2,4,5,5]))
print(singleton([10,10,12,12,15,15,16,18,18]))
print(singleton([1,2,2,5,5,6,6,7,7]))
print(singleton([1,1,2,5,5,6,6,7,7]))
print(singleton([10,10,12,12,15,15,16,16,18]))
输出:
4
16
1
2
18
我不是java专家,因此这可能不是最有效的方法,但它确实有效:
public static int singleton(int[] arr) {
int m = arr.length / 2;
if (m == 0) return arr[0];
if (m % 2 == 1) {
if (arr[m] == arr[m-1]) return singleton(Arrays.copyOfRange(arr, m+1, arr.length));
if (arr[m] != arr[m+1]) return arr[m];
return singleton(Arrays.copyOfRange(arr, 0, m));
}
else {
if (arr[m] == arr[m+1]) return singleton(Arrays.copyOfRange(arr, m+2, arr.length));
if (arr[m] != arr[m-1]) return arr[m];
return singleton(Arrays.copyOfRange(arr, 0, m+1));
}
}
public static void main(String args[])
{
System.out.println(singleton(new int[]{ 1,1,2,2,4,5,5 }));
System.out.println(singleton(new int[]{ 10,10,12,12,15,15,16,18,18 }));
System.out.println(singleton(new int[]{1,2,2,5,5,6,6,7,7}));
System.out.println(singleton(new int[]{1,1,2,5,5,6,6,7,7}));
System.out.println(singleton(new int[]{10,10,12,12,15,15,16,16,18}));
}
我认为应该还有一个限制。也许是关于元素的数量和它们的范围之间的关系。@LiorKogan已经更新了我忽略约束的语句。你没有说明N是什么。请在问题中说明。我假设N是数组的长度,尽管这只是一个猜测。在这种情况下,您不可能在O(logn)中解决这个问题。这并没有足够的时间来检查数组中的每个元素-唯一可行的方法是在不检查每个元素的情况下找到元素。但是数组被排序的事实并不能真正帮助查找非重复元素。是什么让你认为O(logn)中有一个解决方案?@Stef因为所有其他数字正好出现两次,你可以对单个值进行二进制搜索,即
O(logn)
你能帮助java吗solution@dev_mg99请参阅我的编辑。代码即使不是最有效的,也是功能性的。感谢这个解决方案,我在这个“arr[m+1:]”中有点困惑,所以我要求使用java解决方案。@dev_mg99不用担心-在我第一次回答问题时,您没有标记这个问题,所以我只使用了子数组更容易编写的语言。我希望java代码能够清楚地说明arr[m+1://code>的含义(从索引m+1
到结尾的arr
子数组),感谢您提供了一个非常好的解决方案。但在时间复杂度上可能有点问题。在每次函数调用中,您都要创建一个子数组(Arrays.copyOfRange(arr,m+1,arr.length)),它需要O(N)N表示从索引m+1到末尾的arr子数组。我认为这对O(logn)TC不起作用
public static int singleton(int[] arr) {
int m = arr.length / 2;
if (m == 0) return arr[0];
if (m % 2 == 1) {
if (arr[m] == arr[m-1]) return singleton(Arrays.copyOfRange(arr, m+1, arr.length));
if (arr[m] != arr[m+1]) return arr[m];
return singleton(Arrays.copyOfRange(arr, 0, m));
}
else {
if (arr[m] == arr[m+1]) return singleton(Arrays.copyOfRange(arr, m+2, arr.length));
if (arr[m] != arr[m-1]) return arr[m];
return singleton(Arrays.copyOfRange(arr, 0, m+1));
}
}
public static void main(String args[])
{
System.out.println(singleton(new int[]{ 1,1,2,2,4,5,5 }));
System.out.println(singleton(new int[]{ 10,10,12,12,15,15,16,18,18 }));
System.out.println(singleton(new int[]{1,2,2,5,5,6,6,7,7}));
System.out.println(singleton(new int[]{1,1,2,5,5,6,6,7,7}));
System.out.println(singleton(new int[]{10,10,12,12,15,15,16,16,18}));
}