我尝试在线解决一个编程问题(我的作业或我的任何面试/测试,但可能是一个很好的候选人)。 问题如下。我的代码在功能上是正确的,但它具有运行时复杂度O(N 2 ),其中预期的解决方案应该是O(N)。
我尝试了其他一些方法来优化它们 - 1)对数组进行排序,然后尝试我是否可以使用它,但由于排序导致原始数字的索引丢失,我甚至将它们保存在一个单独的数组中并且确实进行了调整,但即使最终也是O(N 2 )。我确信数组的排序有助于达到O(N),但却无法确定它。
使用任何方法在O(N)中完成此问题的任何帮助都会很有用。
(长篇道歉)
考虑N个整数的零索引数组A.该数组的指数是从0到N-1的整数。取索引K.如果A [J]>,则将索引J称为K的上升。 A [K]。注意,如果A [K]是数组A中的最大值,则K没有上升。
如果abs(K-J)是最小可能值(即,如果J和K之间的距离最小),则K的Ascender J被称为K的最近上升者。请注意,K最多可以有两个最接近的上升部分:一个较小,一个比K大。例如,让我们考虑以下数组A:
A [0] = 4 A [1] = 3 A [2] = 1 A [3] = 4 A [4] = -1 A [5] = 2 A [6] = 1 A [7] = 5 A [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):
if K has the closest ascender J, then R[K] = abs(K−J); that is, R[K] is equal to the distance between J and K,
if K has no ascenders then R[K] = 0.
例如,给定以下数组A:
A [0] = 4 A [1] = 3 A [2] = 1 A [3] = 4 A [4] = -1 A [5] = 2 A [6] = 1 A [7] = 5 A [8] = 7
该函数应返回以下数组R:
R [0] = 7 R [1] = 1 R [2] = 1 R [3] = 4 R [4] = 1 R [5] = 2 R [6] = 1 R [7] = 1 R [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(N 2 )):
#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]));
}
答案 0 :(得分:2)
左侧最近的上升者和最近的上升者可以单独考虑。我们经历了一次数组,计算出最近的上升点;再一次在相反的方向,计算最近的上升。最近的上升者是两者中最接近的。
在下面的算法中,只考虑左上方。一堆索引跟踪当前元素的左上升(所有这些)。最近的上升者始终位于堆栈的顶部。
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)
答案 1 :(得分:0)
我的意思是将其添加为评论但未显示任何评论链接。 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;
根据您在下面的评论,这是一个有效的程序。该算法基于计数排序(如http://geekviewpoint.com/Sort_Algorithms_in_java/所示)。 “偏移”是允许负值,如“-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));
}
}
答案 2 :(得分:0)
我不确定是否有Ο( N )解决方案,但这里有一个Ο( N ·log N ) JavaScript中的解决方案:
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];
}
在这里排序值是Ο( N ·log N )的最大努力。
答案 3 :(得分:0)
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));
}
}
答案 4 :(得分:0)
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]; }
}
}
}
答案 5 :(得分:0)
我的解决方案是O(N):
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;
}
}
基本上在搜索功能中,我将数组的第一个元素与右边的元素进行比较,如果它更大,这意味着它是第一个最接近的上升元素。对于其他元素,我比较左边的一个元素,然后紧接着右边的元素。第一个更大的是最接近的上升,我继续这样迭代,直到我找不到比我正在考虑的元素大或我返回0的元素。