如何在没有三个嵌套循环的情况下对三次和编码

如何解决如何在没有三个嵌套循环的情况下对三次和编码

我正在尝试有效地实现类似以下的公式:

sum(i=1,n) sum(j=i+1,n) sum(k=j+1,n) x(i)*x(j)*x(k)

执行此操作的直接方法是:

sum = 0
for (int i=1; i<n; i++ )
    for( int j=i+1; j<n; j++ )
        for( int k=j+1; k<n; k++ )
            sum += x[i]*x[j]*x[k]

问题是这是O(n^3)。我想知道是否有某种方法可以重写 这样我就可以使用某些递归关系消除一层或什至两层迭代。我尝试了以下方法,但是没有运气:

for (int i=n; i>0; i-- )
    int sumK = 0
    for( int j=n; j>i; j-- ) {
         sum += sumK
         sumK += x[i]*x[j]*x[j]
    }

与简单代码相比,它给出了不同的答案,但是它确实消除了一层迭代,所以我认为我处在正确的轨道上(尽管出轨)。有人可以帮忙吗?

解决方法

您可以从以下正式公式开始: formal equation

首先要进行的观察是,由于x_i和x_j相对于k是常数,并且被相乘,因此您可以将它们从求和中排除,从而得到: pulled out

使用相同的逻辑,您可以从另一个求和中提取x_i: pulled out more

现在,您可以看到只需要为每个i < n从i..n计算x中元素的总和(可以使用后缀和在O(n)时间内完成),确保乘以您开始的元素,以解决与x_j的乘法。这占最右边的总和。现在,您可以执行相同的操作,但要获得先前获得的总和,请确保将其乘以您开始的元素的值(以考虑x_i的乘积)。这占中间总和。然后,您可以将之前结果的1到n中的所有值相加,得出最终答案。这是生成的Java代码(查看函数fastProduct):

import java.util.Random;

public class Test {
    public static void printArr(long[] arr) {
        System.out.print("[");
        for (int i = 0; i < arr.length; i ++) {
            System.out.print(arr[i]);
            if (i < arr.length - 1) {
                System.out.print(",");
            }
        }
        System.out.println("]");
    }

    public static long naiveProduct(long[] arr) {
        long sum = 0;
        for (int i = 0; i < arr.length; i ++) {
            for (int j = i + 1; j < arr.length; j ++) {
                for (int k = j + 1; k < arr.length; k ++) {
                    sum += arr[i] * arr[j] * arr[k];
                }
            }
        }
        return sum;
    }

    public static long fastProduct(long[] arr) {
        long[] sums = new long[arr.length];
        sums[arr.length - 2] = arr[arr.length - 1];
        // pre-calculate the summations of x_k
        for (int j = arr.length - 3; j >= 1; j --) {
            sums[j] = sums[j + 1] + arr[j + 1];
        }
        // multiply by x_j
        for (int j = 1; j <= arr.length - 2; j ++) {
            sums[j] *= arr[j];
        }
        long[] sumSums = new long[arr.length];
        sumSums[arr.length - 3] = sums[arr.length - 2];
        // pre-calculate the summations of x_j times the summation of x_k
        for (int i = arr.length - 4; i >= 0; i --) {
            sumSums[i] = sumSums[i + 1] + sums[i + 1];
        }
        // multiply by x_i
        for (int i = 0; i <= arr.length - 3; i ++) {
            sumSums[i] *= arr[i];
        }
        long total = 0;
        // sum up the final summation
        for (int i = 0; i < arr.length - 2; i ++) {
            total += sumSums[i];
        }
        return total;
    }

    public static void main(String[] args) {
        long[] test = new long[10];
        Random rand = new Random();
        for (int i = 0; i < test.length; i ++) {
            test[i] = rand.nextInt(9) + 1;
        }
        printArr(test);
        System.out.printf("%d %d",naiveProduct(test),fastProduct(test));
    }
}
,

以下更新基于earlier Aplet123's answer,由于重新使用了k的最里面的和,它允许通过删除一个嵌套循环来降低复杂性:

static int sum3_fix(int[] x) {
    int sum = 0;
    int tmp = 0; // sum of innermost loop,will be reduced for the following iterations
    int n = x.length;

    for (int i = 0; i < n; i++ ) {
        int tmp2 = 0;
        for(int j = i + 1; j < n; j++ ) {
            if (tmp == 0) { // calculate sum of x[2,n] only once
                for(int k = j + 1; k < n; k++ ) {
                    tmp += x[k];
                }
            } else {
                tmp -= x[j];
            }
            tmp2 += x[j] * tmp;
        }
        sum += x[i] * tmp2;
    }
    return sum;
}

测试:

int[] x = new int[]{1,2,3,4,5,6,7,8,10,15,20};
System.out.println(sum3(x));  // non-optimized implementation
System.out.println(sum3_fix(x));

输出

55506
55506

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?