【问题标题】:Best Algorithm to avoid nested loops without Brute Force approach [closed]在没有蛮力方法的情况下避免嵌套循环的最佳算法[关闭]
【发布时间】:2020-11-25 19:04:45
【问题描述】:

我想让这个方法尽可能快地运行。

int[] p = new int[] {1,4,4,5,1,3,6};
int[] q = new int[] {2,1,3,1,6,4,3};
int k =4.
void nestLoop(){
 for(int i = 0; i < q.length; i++){
     for(int j = 0; j < p.length; j++){
       //code continues 
       // inside here...
       //This approach 
        // takes a longer 
         //time to finish 
         // executing. I need a better algorithm

      }


  }
}

为了更清楚;在q[0]处,p = 1,由于1小于q[0],所以选1,p[4]也更小,选1;因此当它是 q[0] 时的答案是 1 和 1 :但是因为 1 和 1 是两个整数,所以它们不等于 k ​​= 4,然后返回 0。如果答案是 1, 1,1,1 那么数字是4,等于k。 [1,1,1,1] 将被返回。其他q也一样

【问题讨论】:

标签: java algorithm nested-loops brute-force


【解决方案1】:

如果我理解正确,您返回的是 k 或 0,对吗?

那么就是这样做的:

int[] p = new int[] {1,4,4,5,1,3,6};
int[] q = new int[] {2,1,3,1,6,4,3};
int k =4.

void notNested()
{
    TreeSet<Integer> ts = new TreeSet<Integer>();
    // Find the kth smallest number in the array.
    PriorityQueue<Integer> pq = new PriorityQueue<>(Comparator.reverseOrder());
    for (int p1 : p)
    {
        if (pq.size() < k)
        {
            pq.add(p1);
        } else if (pq.peek() > p1)
        {
            pq.poll();
            pq.add(p1);
        }
    }

    int ksm = pq.poll();
    // For each q, compare against kth smallest only.
    for (int q1 : q)
    {
        if (q1 >= ksm)
        {
            results.add(k);
        }
        else
        {
            results.add(0);
        }
    }
}

【讨论】:

  • 这不关心p中项目的顺序,对吧?这可能很好,虽然我理解 OP 意味着 first k 元素更小q[i].
  • 它只返回 p 中最小的 k 个项目,因为这决定了它是否可能。如果问题需要小于 q[i] 的“第一个”k 个元素,那么在不知道约束的情况下,如果没有嵌套循环就很难优化它,因为我们可能会耗尽内存。
【解决方案2】:

这是一个使用 Java Streams 的解决方案:

package javaapplication3;
import java.util.Arrays;
import java.util.stream.*;

public class JavaApplication3 {
    public static void main(String[] args) {

        int[] p = new int[] {1,4,4,5,1,3,6};
        int[] q = new int[] {2,1,3,1,6,4,3};
        int[][] results = new int[q.length][]; // Array of arrays to store results
        int k =4;
        
        // For each element q[i], execute in parallel
        IntStream.range(0, q.length).parallel().forEach(i -> {
            final int qi = q[i];
            // Get first k elements of p <= q[i]
            results[i] = Arrays.stream(p).filter(v -> v <= qi).limit(k).toArray();            
        });
        
        for(int i=0; i<q.length; i++) {
            int[] result = results[i];
            System.out.print("Values less or equal than " + q[i] + ": {");
            for (int v : result)
                System.out.print(" " + v);
            System.out.println(" }");
        }

    }    
}

输出:

Values less or equal than 2: { 1 1 }
Values less or equal than 1: { 1 1 }
Values less or equal than 3: { 1 1 3 }
Values less or equal than 1: { 1 1 }
Values less or equal than 6: { 1 4 4 5 }
Values less or equal than 4: { 1 4 4 1 }
Values less or equal than 3: { 1 1 3 }

注意:您可以选择对 p 进行排序,如果 p 大而 k 小,这将提高性能。

【讨论】:

  • 如果我错了,请纠正我,但这基本上仍然是完全相同的算法,只是使用流,对吗?我想如果 OP 只是想“避免(显式)循环”,这很好,但它可能不会更快。
  • @tobias_k 你是对的。我在我的一个 cmets 中向 OP 提到了这一点。也就是说,我提供了使用所有内核的可能性。此外,在没有 p、q 和 k 的相对大小信息的情况下,我们只能猜测最好的算法可能是什么。
【解决方案3】:

如果p 中的不同 元素的数量与 元素的数量相比相对较少,则以下方法可能有效。但是,如果有许多不同的元素,甚至所有元素都不同,那么它会慢很多。

  • 创建一个Map 将元素映射到它们的索引,例如[1,4,4,5,1,3,6] 将变为 {1: [0,4], 4: [1,2], 5: [3], 3: [5], 6: [6]}
  • 从该映射中,获取小于来自q 的当前元素的所有元素的索引列表
  • 将它们放入堆或优先队列中,按该元素的下一个未使用索引排序
  • 从堆中弹出列表,获取第一个索引,然后将它们放回堆中以获取下一个索引,直到获得 k 索引

如果有很多重复的元素(并且只有这样),这可能会在一定程度上降低复杂性。对于p 中的P 元素,d 中不同的元素,Q 中的元素qk,这应该具有O(P + Q*(d+k*log(d))) 的复杂性(P 用于创建地图,以及d 用于选择列表,k 堆操作与log(d) 用于所有Q 查询)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-29
    • 2019-10-08
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2021-08-27
    相关资源
    最近更新 更多