Optimization 如何使执行时间从O(N^2)变为O(N)

Optimization 如何使执行时间从O(N^2)变为O(N),optimization,Optimization,我试图在线解决一个编程问题(既不是我的家庭作业,也不是我的任何面试/测试,但可能是一个很好的候选人)。 下面给出了问题。我下面的代码在功能上是正确的,但它的运行时复杂性是O(N2),正如解决方案所期望的那样,应该是O(N) 我尝试了两种其他方法来优化它-1)对数组进行排序,然后尝试是否可以让它工作,但由于排序会导致原始数字的索引丢失,我甚至将它们保留在单独的数组中,并解决了它,但即使是O(N2)。我确信数组的排序将有助于达到O(N),但只是无法确定它 使用任何方法在O(N)中完成此问题的任何帮助

我试图在线解决一个编程问题(既不是我的家庭作业,也不是我的任何面试/测试,但可能是一个很好的候选人)。 下面给出了问题。我下面的代码在功能上是正确的,但它的运行时复杂性是O(N2),正如解决方案所期望的那样,应该是O(N)

我尝试了两种其他方法来优化它-1)对数组进行排序,然后尝试是否可以让它工作,但由于排序会导致原始数字的索引丢失,我甚至将它们保留在单独的数组中,并解决了它,但即使是O(N2)。我确信数组的排序将有助于达到O(N),但只是无法确定它

使用任何方法在O(N)中完成此问题的任何帮助都是有用的

(为冗长的帖子道歉)

考虑一个由N个整数组成的零索引数组。此数组的索引是0到N之间的整数−1.取一个索引K。如果A[J]>A[K],则索引J称为K的递增项。注意,如果A[K]是数组A中的最大值,则K没有递增项

如果abs(K),则K的上升点J称为K的最近上升点−J) 是可能的最小值(即,如果J和K之间的距离最小)。注意,K最多可以有两个最近的上升点:一个比K小,一个比K大

例如,让我们考虑以下数组A:

A[0]=4A[1]=3A[2]=1A[3]=4A[4]=1A[5]=2A[6]=1A[7]=5A[8]=7

如果K=3,那么K有两个上升点:7和8。它最近的上升点是7,K和7之间的距离等于abs(K−7) =4

编写一个函数:

struct Results {
  int * R;
  int N;
};

struct Results array_closest_ascenders(int A[], int N);
给定一个由N个整数组成的零索引数组a,返回一个由N个整数组成的零索引数组R,这样(对于K=0,…,N−1) :

例如,给定以下数组A:

A[0]=4A[1]=3A[2]=1A[3]=4A[4]=1A[5]=2A[6]=1A[7]=5A[8]=7

函数应返回以下数组R:

R[0]=7R[1]=1R[2]=1R[3]=4R[4]=1R[5]=2R[6]=1R[7]=1R[8]=0

数组R应返回为:

    a structure Results (in C), or
    a vector of integers (in C++), or
    a record Results (in Pascal), or
    an array of integers (in any other programming language).
假设:

    N is an integer within the range [0..50,000];
    each element of array A is an integer within the range [−1,000,000,000..1,000,000,000].
复杂性:

    expected worst-case time complexity is O(N);
    expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
可以修改输入数组的元素

我的解决方案(O(N2)):

#include <math.h>
#include "stdio.h"
#include "stdlib.h"

struct Results
{
    int *R;
    int N;
};

struct Results array_closest_ascenders ( int A[], int N )
{
    struct Results result;


     int i,j,asc_found=0;

     result.R = (int*)malloc(sizeof(int)*N);

     for(i=0;i<N;i++)
       result.R[i] = N;

     result.N = N;

     for(i=0;i<N;i++)
     {
       asc_found = 0;
       for(j=0;j<N;j++)
       {
         if(A[i] < A[j])
         {
           //if(result.R[i] == 0)
           {
               if(result.R[i] > abs(i-j))
               {
                    result.R[i] = abs(i-j);
                    asc_found = 1;
               }
           }
         }
       }
       if(asc_found == 0)
           result.R[i] = 0;
     }


    return result;
}

void main()
{

    //int A[] = {4, 3, 1, 4, -1, 2, 1, 5, 7};
    int A[] = {691446939, -241956306, 485954938, 604054438, 383714185, -656099986, -357341170, -255988102, -139683363, -463281394, -382925609, 712727854};
    struct Results tmp;

    tmp = array_closest_ascenders(A,sizeof(A)/sizeof(A[0]));

}
#包括
#包括“stdio.h”
#包括“stdlib.h”
结构结果
{
int*R;
int N;
};
结构结果数组\u最近的\u递增项(int A[],int N)
{
结构结果;
inti,j,asc_=0;
结果R=(int*)malloc(sizeof(int)*N);

对于(i=0;i我想将其添加为注释,但没有显示注释链接。R[]是否应该跟随

R[0]=abs(0-7)=7;
R[1]=abs(1-0)=1;
R[2]=abs(2-5)=3;
R[3]=abs(3-7)=4;
R[4]=abs(4-2)=2;/or 4-6
R[5]=abs(5-1)=4;
R[6]=abs(6-5)=1;
R[7]=abs(7-8)=1;
R[8]=abs(8-8)=0;
根据您在下面的评论,这是一个有效的程序。该算法基于计数排序(如上所示)。“偏移量”允许出现“-1”之类的负值

注意:尽管有一个用于填充R[]的嵌套循环,但该算法不是N^2,因为第二个循环在桶的数量上迭代

回答:[7,1,1,4,1,2,1,1,0]

import java.util.ArrayList;
import java.util.Arrays;

public class Ascender {
public static int[] ascenderArray(int[] A) {
    int max = A[0], min = A[0];
    for (int i : A) {
        if (max < i)
            max = i;
        if (min > i)
            min = i;
    }
    int offset = min < 0 ? -min : 0;
    ArrayList<Integer> buckets[] = new ArrayList[max + 1 + offset];
    for (int i = 0; i < buckets.length; i++)
        buckets[i] = new ArrayList<Integer>();
    for (int i = 0; i < A.length; i++)
        buckets[A[i] + offset].add(i);

    int[] R = new int[A.length];
    for (int i = 0; i < R.length; i++) {
        try {
            min = A.length;
            int x = A[i] + 1 + offset;
            for (int n = x; n < buckets.length; n++) {
                x=n;
                while (buckets[x].isEmpty())
                    x++;
                n=x;
                int tmp = Math.abs(i - buckets[n].get(0));
                if (min > tmp)
                    min = tmp;
            }
            R[i] = min==A.length?0:min;
        } catch (Exception e) {
            R[i] = 0;
        }
    }
    return R;
}//

public static void main(String... args) {
    int A[] = { 4, 3, 1, 4, -1, 2, 1, 5, 7 };
    int R[] = ascenderArray(A);
    System.out.println(Arrays.toString(R));
}
}
import java.util.ArrayList;
导入java.util.array;
公共阶级上升者{
公共静态int[]上行阵列(int[]A){
int max=A[0],min=A[0];
对于(int i:A){
如果(最大值i)
min=i;
}
int offset=min<0?-min:0;
ArrayList bucket[]=新的ArrayList[max+1+偏移];
对于(int i=0;itmp)
min=tmp;
}
R[i]=min==A.length?0:min;
}捕获(例外e){
R[i]=0;
}
}
返回R;
}//
公共静态void main(字符串…参数){
inta[]={4,3,1,4,-1,2,1,5,7};
int R[]=上升线(A);
System.out.println(Arrays.toString(R));
}
}
左最近升序和右最近升序可以分别考虑。我们在数组中遍历一次,计算左最近升序;然后在相反方向上再次计算右最近升序。最近升序是两个升序中的较近者

在下面的algo算法中,只考虑左上升键。索引堆栈跟踪当前元素的左上升键(全部)。最近的上升键始终位于堆栈顶部

for i in 0 .. N
  while (!stack.empty) && (A[stack.top] <= A[i])
    stack.pop
  if stack.empty
    then R[i] = 0
    else R[i] = i - stack.top
  stack.push(i)
0..N中的i的


虽然(!stack.empty)&&(A[stack.top]我不确定是否有一个Ⅹ(N)解决方案,但这里有一个JavaScript中的Ⅹ(N·log N)解决方案:

var A = [4,3,1,4,-1,2,1,5,7],
    N = A.length;

// build an array of index:value pairs and sort them in ascending order
var sorted = [];
for (var i=0; i<N; i++) {
    sorted.push({index:i, value:A[i]});
}
sorted.sort(function(a, b) { return a.value - b.value; });

// iterate the sorted array in descending order
var ascenders = [],
    closest,            // closest ascender
    curr = sorted[N-1]; // initiate curr with largest item
ascenders[N-1] = 0;
for (var i=N-2; i>=0; i--) {
    // compare curr from the previous iteration with the future
    // curr of the current iteration
    if (sorted[i].value !== curr.value) {
        // update closest ascender if their values differ
        closest = curr;
    }
    curr = sorted[i];
    ascenders[i] = Math.abs(curr.index-closest.index);
}

// rearrange ascenders in the original order
var ret = [];
for (var i=0; i<N; i++) {
    ret[sorted[i].index] = ascenders[i];
}
var A=[4,3,1,4,-1,2,1,5,7],
N=A.长度;
//构建一个索引:值对数组,并按升序排序
var排序=[];
对于(变量i=0;i=0;i--){
//将上一次迭代的curr与将来的curr进行比较
//当前迭代的curr
if(已排序[i].value!==当前值){
//如果它们的值不同,则更新最近的提升器
最近值=当前值;
}
curr=已排序的[i];
升序器[i]=数学绝对值(当前索引最接近的索引);
}
//按原始顺序重新排列升序器
var-ret=[];
对于(var i=0;i
import java.util.array;
导入java.util.TreeMap;
公共类AsenderUtil{
公共静态int[]GetCloseStatSenderInDices(int[]arr,int indx){
if(indx<0 | | arr.length
类程序
{
静态void Main(字符串[]参数)
{
int[]A=新的int[]{4,3,1,4,-1,2,1,5,7};
int[]B=新的int[A.长度];
int[]R=新的int[A.长度];
Program obj=新程序();
对象ABC(A、B、R);
}
公共无效ABC(int[]A,int[]B,int[]R)
{
int i,j,m,k
var A = [4,3,1,4,-1,2,1,5,7],
    N = A.length;

// build an array of index:value pairs and sort them in ascending order
var sorted = [];
for (var i=0; i<N; i++) {
    sorted.push({index:i, value:A[i]});
}
sorted.sort(function(a, b) { return a.value - b.value; });

// iterate the sorted array in descending order
var ascenders = [],
    closest,            // closest ascender
    curr = sorted[N-1]; // initiate curr with largest item
ascenders[N-1] = 0;
for (var i=N-2; i>=0; i--) {
    // compare curr from the previous iteration with the future
    // curr of the current iteration
    if (sorted[i].value !== curr.value) {
        // update closest ascender if their values differ
        closest = curr;
    }
    curr = sorted[i];
    ascenders[i] = Math.abs(curr.index-closest.index);
}

// rearrange ascenders in the original order
var ret = [];
for (var i=0; i<N; i++) {
    ret[sorted[i].index] = ascenders[i];
}
import java.util.Arrays;
import java.util.TreeMap;

public class AsenderUtil {

    public static int[] getClosestAsenderIndices(int[] arr, int indx) {

        if (indx < 0 || arr.length <= indx)
            throw new RuntimeException("wrong input");

        int baseVal = arr[indx];

        TreeMap<Integer,Integer> ts = new TreeMap<Integer,Integer>();

        for(int i=0;i<arr.length;i++){
            if(arr[i]>baseVal) {
                ts.put(Math.abs(i-indx),i);
            }
        }

        int[] toReturn = new int[2];
        toReturn[0] = ts.remove(ts.firstKey());
        toReturn[1] = ts.remove(ts.firstKey());

        return toReturn;
    }

    public static void main(String... args) {
        int A[] = { 4, 3, 1, 4, -1, 2, 1, 5, 7 };
        int R[] = getClosestAsenderIndices(A,3);
        System.out.println(Arrays.toString(R));
    }
}
class Program
{
    static void Main(string[] args)
    {
        int[] A = new int[] { 4, 3, 1, 4, -1, 2, 1, 5, 7 };
         int[] B = new int[A.Length];
        int[] R = new int[A.Length];
        Program obj = new Program();
        obj.ABC(A,B, R);
    }

    public void ABC(int[] A,int[]B, int[] R)
    {
        int i, j, m,k;
        // int temp = 0;
        int n = A.Length - 1;
        for (i = 0; i < n; i++)
        {
            for (j = 0; j <= n; j++)
            {
                if (A[i] < A[j])
                {
                    m = Math.Abs(j - i);
                    R[i] = m;
                    break;

                }

            }
            for (j = i-1; j > 0; j--)
            {
                if (A[i] < A[j])
                {
                    k = Math.Abs(j - i);
                    B[i] = k;
                    break;

                }

            }

        }
        for (i = 0; i < n; i++)
        {
            if (R[i] > B[i] && (B[i] == 0))
            {

                R[i] = R[i];
                //Console.WriteLine(R[i]);
                //Console.ReadLine();
            }

            else { R[i] = B[i]; }
        }


    }
}
class ArrayClosestAscendent {
 public int[] solution(int[] A) {
     int i;
     int r[] = new int[A.length];
     for(i=0;i<A.length;i++){
         r[i] = search(A, i);
     }
     return r;
 }

public int search(int[] A, int i) {
    int j,k;
    j=i+1;
    k=i-1;
    int result = 0;
    if(j <= A.length-1 && (A[j]>A[i]))
            return Math.abs(j-i);
    j++;
     while(k>=0 || j < A.length){
         if(k >= 0 && A[k] > A[i]){
             return Math.abs(i-k);
         }else if(j < A.length && A[j] > A[i]){
             return Math.abs(i-j);
         }else{
             j++;
             k--;
         }
     }
     return result;
}    
}