面试 - 在阵列中查找幅度极点

时间:2013-03-13 22:21:58

标签: algorithm

Magnitude Pole:数组中的一个元素,其左侧元素小于或等于它,右侧元素大于或等于它。

示例输入

3,1,4,5,9,7,6,11

所需的输出

4,5,11

我在面试中被问到这个问题,我必须返回元素的索引,只返回符合条件的第一个元素。

我的逻辑

  
      
  1. 取两个MultiSet(这样我们也可以考虑复制),一个用于元素的右侧,一个用于左侧的   元素(极点)。
  2.   
  3. 从第0个元素开始,将所有元素放在“右边的集合”中。
  4.   
  5. 如果第0个元素小于或等于“right set”上的所有元素,则返回基本条件,然后返回其索引。
  6.   
  7. 否则将其放入“左侧集合”并从索引1处的元素开始。
  8.   
  9. 遍历数组,每次从“左设置”中选择最大值,从“右设置”中选择最小值并进行比较。
  10.   
  11. 在任何元素的任何时刻,左侧的所有值都在“左侧集合”中,右侧的值在“右侧集合”中
  12.   

代码

int magnitudePole (const vector<int> &A) {  
   multiset<int> left, right;        
   int left_max, right_min;          
   int size = A.size();
   for (int i = 1; i < size; ++i)
       right.insert(A[i]);
   right_min = *(right.begin()); 
   if(A[0] <= right_min)
       return 0;
   left.insert(A[0]);
   for (int i = 1; i < size; ++i) {
       right.erase(right.find(A[i]));
       left_max = *(--left.end());
       if (right.size() > 0)
           right_min = *(right.begin());
       if (A[i] > left_max && A[i] <= right_min)
           return i;
       else
           left.insert(A[i]);
   }
   return -1;
}

我的问题

  
      
  • 我被告知我的逻辑不正确,我无法理解为什么这个逻辑是不正确的(虽然我检查了一些情况和   它正在返回正确的索引)
  •   
  • 为了我自己的好奇心如何在O(n)时间内不使用任何set / multiset来做到这一点。
  •   

8 个答案:

答案 0 :(得分:9)

对于O(n)算法:

  1. 对[0,length(n))中的所有k计算从n [0]到n [k]的最大元素,将答案保存在数组maxOnTheLeft中。这需要花费O(n);
  2. 对[0,length(n))中的所有k计算从n [k]到n [length(n)-1]的最小元素,将答案保存在数组minOnTheRight中。这需要花费O(n);
  3. 遍历整个事物并找到任何n [k] with maxOnTheLeft&lt; = n [k]&lt; = minOnTheRight。这需要花费O(n)。
  4. 你的代码(至少)错了:

    if (A[i] > left_max && A[i] <= right_min) // <-- should be >= and <=
    

答案 1 :(得分:3)

  • 创建两个名为NorthPole和SouthPole的bool [N](只是为了幽默。
  • 向前迈进A []追踪到目前为止找到的最大元素,并设置SouthPole [i]如果A [i]&gt;最大值(A [0..i-1])
  • 通过A []后退,如果A [i] <1,则设置NorthPole [i]为真。分(A [1 + 1..N-1)
  • 向前走过NorthPole和SouthPole找到第一个元素,并设置为true。

O(N)在上面的每个步骤中,作为访问每个节点一次,所以O(N)整体。

答案 2 :(得分:3)

Java实现:

Collection<Integer> magnitudes(int[] A) {
    int length = A.length;
    // what's the maximum number from the beginning of the array till the current position
    int[] maxes = new int[A.length];
    // what's the minimum number from the current position till the end of the array
    int[] mins = new int[A.length];

    // build mins
    int min = mins[length - 1] = A[length - 1];
    for (int i = length - 2; i >= 0; i--) {
        if (A[i] < min) {
            min = A[i];
        }
        mins[i] = min;
    }

    // build maxes
    int max = maxes[0] = A[0];
    for (int i = 1; i < length; i++) {
        if (A[i] > max) {
            max = A[i];
        }
        maxes[i] = max;
    }

    Collection<Integer> result = new ArrayList<>();
    // use them to find the magnitudes if any exists
    for (int i = 0; i < length; i++) {
        if (A[i] >= maxes[i] && A[i] <= mins[i]) {
            // return here if first one only is needed
            result.add(A[i]);
        }
    }
    return result;
}

答案 3 :(得分:1)

你的逻辑似乎完全正确(虽然没有检查实现),并且可以实现给出O(n)时间算法!很好的工作思维方式。

你的右集可以实现为支持min的堆栈,而左集可以实现为支持max的堆栈,这给出了O(n)时间算法。

拥有支持max / min的堆栈是一个众所周知的面试问题,可以完成每个操作(push / pop / min / max为O(1))。

要将此用作逻辑,伪代码看起来像这样

foreach elem in a[n-1 to 0]
    right_set.push(elem)

while (right_set.has_elements()) {
   candidate = right_set.pop();
   if (left_set.has_elements() && left_set.max() <= candidate <= right_set.min()) {
       break;
   } else if (!left.has_elements() && candidate <= right_set.min() {
        break;
   }
   left_set.push(candidate);
}

return candidate

答案 4 :(得分:1)

我在Codility上看到了这个问题,用Perl解决了它:

sub solution {
        my (@A) = @_;            

        my ($max, $min) = ($A[0], $A[-1]);
        my %candidates;

        for my $i (0..$#A) {
                if ($A[$i] >= $max) {
                        $max = $A[$i];
                        $candidates{$i}++;
                }
        }
        for my $i (reverse 0..$#A) {
                if ($A[$i] <= $min) {
                        $min = $A[$i];
                        return $i if $candidates{$i};
                }
        }
        return -1;
}

答案 5 :(得分:0)

以下代码怎么样?我认为在最坏的情况下效率并不好,但预计效率会很好。

    int getFirstPole(int* a, int n)
{
    int leftPole = a[0];
    for(int i = 1; i < n; i++)
    {
        if(a[j] >= leftPole)
        {
            int j = i;
            for(; j < n; j++)
            {
                if(a[j] < a[i])
                {
                    i = j+1;  //jump the elements between i and j                   
                    break;
                }
                else if (a[j] > a[i])
                    leftPole = a[j];
            }
            if(j == n) // if no one is less than a[i] then return i
                return i;
        }
    }
    return 0;
}

答案 6 :(得分:0)

  1. 创建名为mags的int数组和名为maxMag的int变量。
  2. 对于源数组中的每个元素,检查元素是否大于或等于maxMag
  3. 如果是:将元素添加到mags数组并设置maxMag = element
  4. 如果不是:循环通过mags数组并删除所有较小的元素。
  5. 结果:数组极数

答案 7 :(得分:0)

有趣的问题,我在C#中拥有自己的解决方案,我在下面给出了解决方案以了解我的方法。

public int MagnitudePoleFinder(int[] A)
{
    //Create a variable to store Maximum Valued Item i.e. maxOfUp
    int maxOfUp = A[0];

    //if list has only one value return this value
    if (A.Length <= 1) return A[0];

    //create a collection for all candidates for magnitude pole that will be found in the iteration
    var magnitudeCandidates = new List<KeyValuePair<int, int>>();

    //add the first element as first candidate
    var a = A[0];
    magnitudeCandidates.Add(new KeyValuePair<int, int>(0, a));

    //lets iterate
    for (int i = 1; i < A.Length; i++)
    {
        a = A[i];
        //if this item is maximum or equal to all above items ( maxofUp will hold max value of all the above items)
        if (a >= maxOfUp)
        {
            //add it to candidate list
            magnitudeCandidates.Add(new KeyValuePair<int, int>(i, a));
            maxOfUp = a;
        }
        else
        {
            //remote all the candidates having greater values to this item
            magnitudeCandidates = magnitudeCandidates.Except(magnitudeCandidates.Where(c => c.Value > a)).ToList();
        }
    }
    //if no candidate return -1
    if (magnitudeCandidates.Count == 0) return -1;
    else
        //return value of first candidate
        return magnitudeCandidates.First().Key;
}