我本来应该编写一个代码来说明一个数组是否有重复。运行时并不重要。我认为我的下面的代码会有O(n²)
,因为我使用了嵌套的for循环。我知道有比我写的更好更快的代码,但我的问题是我在if语句中创建的break
语句是否会使我的代码更快一些?它应该让它更快,因为程序知道"嘿,我们发现重复,我们可以停止搜索更多"。我曾经从一位同学那里听说,如果我避免使用return
或break
等语句,代码会更好/更稳定。太糟糕了我当时没有足够的关心来问为什么。也许你可以告诉我这是否属实?
如果他是对的,这些陈述会伤害"我的代码,还有更好的解决方法吗?
public class FindDuplicate{
public static void main(String[] args){
int[] A={1,2,3,4,5,6,7,8,4};
boolean bool=false;
for(int i=0; i<A.length; i++){
for(int j=0; j<A.length; j++){
if(A[i]==A[j] && i!=j){
bool=true;
break;
}
}
}
if(bool==true){
System.out.print("Duplicate found");
}else{
System.out.print("No duplicate found");
}
}
}
答案 0 :(得分:2)
但是,并非在所有情况下,在大多数情况下,考虑到当您找到自己之后的内容时不必继续迭代,它确实会使您的代码更快。我的问题是我在if语句中创建的break语句 会让我的代码(有点)更快吗?
下面的算法包含两个嵌套循环。外部循环遍历所有数组的N
项,因此需要O(N)
个步骤。
对于通过外部循环的每次旅行,内部循环也迭代数组中的N
项,因此它也是takes O(N)
步。
由于一个循环嵌套在另一个循环中,因此组合性能为O(N × N) = O(N2)
。
for(int i = 0; i < A.length; i++){
for(int j=0; j < A.length; j++){
if(A[i] == A[j] && i != j){
bool = true;
break;
}
}
}
我们可以通过在外循环的每次迭代中不返回j = 0
来使您的算法更快一些。
for(int i = 0; i < A.length; i++){
for(int j = i+1; j < A.length; j++){
if(A[i] == A[j]){
bool = true;
break;
}
}
}
请注意,在这种情况下,我们不需要检查&& i != j
,因为它们永远不会相等。
我曾经从一位同学那里听说代码更好/更多 如果我避免返回或中断等语句
,则稳定
使用JVM
时,break
规范未说明是否存在性能损失。简而言之,没有任何证据表明使用break
或return
会使您的代码不稳定(不管怎样我都不知道)。我会说的唯一情况&#34;哦,这不是一个好的做法&#34;是你过度使用单词break
的时候。但是,在许多情况下break
是唯一可能更快完成任务的可能性,例如您当前的解决方案。基本上,为什么当你找到你所追求的东西后继续进行迭代?我认为return
也不是&#34;一个不好的做法&#34;因为类似于break
,为什么在你不需要时继续执行代码,这肯定会让你的代码更快。
当然我们可以考虑java中的Set
接口,该接口不允许重复,并且它基于散列表数据结构,因此插入平均需要O(1)
次。通过使用HashSet
,一个通用Set
实现,我们可以在O(n)
时间内找到重复项。由于HashSet
仅允许使用唯一元素,因此当您尝试添加重复项时,add()
方法将失败并返回false
。
<强>解决方案:强>
public static boolean hasDuplicate(int[] array) {
Set<Integer> dupes = new HashSet<Integer>();
for (Integer i : array) {
if (!dupes.add(i)) {
return true; // we have found a duplicate
}
}
return false; // no duplicate
}
答案 1 :(得分:1)
实际上,您不需要bool
标志变量,也不需要使用break
。 return
将停止迭代,如果没有找到重复,则返回false:
private static boolean findDuplicateOriginal(int[] A) {
for(int i=0; i<A.length; i++){
for(int j=0; j<A.length; j++){
if(A[i]==A[j] && i!=j){
return true;
}
}
}
return false;
}
只需指出性能不应该是编码时的唯一目标。您应该担心维护或编写较少/干净的代码,因为担心性能。 它取决于上下文(调用该函数的频率,它应该执行多少次迭代,它将使用paralelStream运行吗?...)您的应用程序运行以选择一种或另一种方式。
有很多帖子谈论循环性能与流性能以及支持和反对意见:
我只想向您展示干净(1行!)是否对同一个purpouse使用Java8语法:
import java.util.Arrays;
public class test {
public static void main(String[] args) {
int[] A = {1,2,3,4,5,6,7,8,9};
System.out.println(Arrays.toString(A) + " using findDuplicate >> " + findDuplicate(A));
System.out.println(Arrays.toString(A) + " using findDuplicateOriginal >>" + findDuplicateOriginal(A));
int[] B = {1,1,3,4,5,6,7,8,4};
System.out.println(Arrays.toString(B) + " using findDuplicate >> " + findDuplicate(B));
System.out.println(Arrays.toString(B) + " using findDuplicateOriginal >> " + findDuplicateOriginal(B));
}
// using streams
private static boolean findDuplicate(int[] items) {
return !(Arrays.stream(items).distinct().count() == items.length);
}
// refactored original version
private static boolean findDuplicateOriginal(int[] A) {
for(int i=0; i<A.length; i++){
for(int j=0; j<A.length; j++){
if(A[i]==A[j] && i!=j){
return true;
}
}
}
return false;
}
}
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9] using findDuplicate >> false
[1, 2, 3, 4, 5, 6, 7, 8, 9] using findDuplicateOriginal >>false
[1, 1, 3, 4, 5, 6, 7, 8, 4] using findDuplicate >> true
[1, 1, 3, 4, 5, 6, 7, 8, 4] using findDuplicateOriginal >> true