简体   繁体   English

C++ 相邻值

[英]C++ adjacent values

I saw the following question, while managed to solve it in O(n^2) I think we can do better.我看到了以下问题,虽然设法在 O(n^2) 中解决了它,但我认为我们可以做得更好。

Given a vector of integers return the maximum number of non-adjacent copies of similar number.给定一个整数向量,返回相似数的非相邻副本的最大数量。

For example, given: [9,2,3,4,0,4,5,6,0,8]例如,给定:[9,2,3,4,0,4,5,6,0,8]

we can see that we have 2 non adjacent 0 and 2 non adjacent 4 (the rest are ones) so the answer is max(2,2)=2;我们可以看到我们有 2 个不相邻的 0 和 2 个不相邻的 4(rest 是一个)所以答案是 max(2,2)=2;

given: [4,4,4,4,4]给定:[4,4,4,4,4]

we have 3 non adjacent 4 so the answer is 3. we take first 4, then we can't take the one next to it (they are adjacent) so we take the one after and so on.我们有 3 个不相邻的 4,所以答案是 3。我们先取 4,然后我们不能取它旁边的一个(它们是相邻的),所以我们取后面的一个,依此类推。

My solution: Iterate over the vector and check how many non adjacent copies we see from the current number, if it's bigger than current max we update max accordingly.我的解决方案:遍历向量并检查我们从当前数字中看到了多少非相邻副本,如果它大于当前最大值,我们相应地更新最大值。

Q: How can we solve this more efficiently?问:我们怎样才能更有效地解决这个问题?

If you're fine with using O(n) space, you can use buckets for the values you see to achieve an O(n) runtime.如果您对使用 O(n) 空间感到满意,则可以将存储桶用于您看到的值以实现 O(n) 运行时。

The easiest way to implement that would be with a map.最简单的实现方法是使用 map。 ie: IE:

std::pair<int, int> max_adj(std::vector<int> arr) {
    std::map<int, int> buckets;
    
    for(int x = 0; x < arr.size(); x++) {
        // Loop to eat up adjacent values
        int in_a_row = 1;
        for(int curr = x++;
            x < arr.size() && arr[curr] == arr[x];
            x++, in_a_row++) { }
        x--; // The loop will increment x one past last dupe, so go back
        
        // Only count every other adjacent value seen
        buckets[arr[x]] += (in_a_row + 1) / 2;
    }
    
    // Find the most seen
    std::map<int, int>::iterator mx = std::max_element
    (
        buckets.begin(), buckets.end(),
        [] (const std::pair<int, int> &p1, const std::pair<int, int> &p2) {
            return p1.second < p2.second;
        }
    );
    
    if(mx != buckets.end()) {
        return *mx;
    }
    return std::pair<int, int>(-1, -1);
}

Live example: https://ideone.com/v9OOIA现场示例: https://ideone.com/v9OOIA

This problem can be solved by creating an array which contains number and it's index as showed below,这个问题可以通过创建一个包含数字及其索引的数组来解决,如下所示,

original array = [9, 2, 3, 4, 0, 4, 5, 6, 0, 8] ,原始数组 = [9, 2, 3, 4, 0, 4, 5, 6, 0, 8] ,
number index array = [ 9 , 0], [ 2 , 1], [ 3 , 2], [ 4 , 3], [ 0 , 4], [ 4 , 5], [ 5 , 6], [ 6 , 7], [ 0 , 8], [ 8 , 9]数字索引数组 = [ 9 , 0], [ 2 , 1], [ 3 , 2], [ 4 , 3], [ 0 , 4], [ 4 , 5], [ 5 , 6], [ 6 , 7 ]、[ 0 ]、[ 8 ]

Here first element of std::pair is number itself and second element is index of number.这里std::pair的第一个元素是数字本身,第二个元素是数字的索引。
After it, sort this array by numbers and result would be as follows,之后,按数字对该数组进行排序,结果如下,
[ 0 , 8], [ 0 , 4], [ 2 , 1], [ 3 , 2], [ 4 , 5], [ 4 , 3], [ 5 , 6], [ 6 , 7], [ 8 , 9], [ 9 , 0] [ 0 , 8], [ 0 , 4], [ 2 , 1], [ 3 , 2], [ 4 , 5], [ 4 , 3], [ 5 , 6], [ 6 , 7], [ 8 , 9], [ 9 , 0]

Purpose of sorting is to bring same numbers adjacent to each other.排序的目的是使相同的数字彼此相邻。 Once same numbers are adjacent a simple iteration is required to find answer.一旦相同的数字相邻,就需要简单的迭代来找到答案。 Let's see how it works,让我们看看它是如何工作的,

First number in sorted array is 0 and by finding upper bound of 0 will give all adjacent 0 , it means following will be available,排序数组中的第一个数字是0并且通过找到0upper bound将给出所有相邻的0 ,这意味着以下将可用,
[ 0 , 8], [ 0 , 4] [ 0 , 8], [ 0 , 4]
But As you can see above these entries are not in order of index entry of index 4 is following entry of index 8 and this is because std::sort is not a stable sort, it means relative order of elements are not preserved.但是正如您在上面看到的,这些条目不是按照索引4的索引条目的顺序在索引8的条目之后,这是因为std::sort不是稳定的排序,这意味着元素的相对顺序不会被保留。 So before proceeding these elements have to sort again by index and result would be因此,在继续之前,这些元素必须再次按索引排序,结果将是

[ 0 , 4], [ 0 , 8] [ 0 , 4], [ 0 , 8]
As showed above index 4 and 8 are not adjacent 4 + 1 != 8 , and count of non adjacent numbers is two .如上所示,索引48不相邻4 + 1 != 8 ,非相邻数字的计数为two

All entries of 0 are examined, and algorithm will consider next number which is 2 , but as you see above in array there is only one entry of number 2 which is [2, 1] and due to this next number will be considered, same will happen for all numbers so let directly see number 4 and it has more then one entries as showed below,检查0的所有条目,算法将考虑下一个数字2 ,但正如您在上面看到的数组中只有一个数字2的条目,即[2, 1]并且由于这个下一个数字将被考虑,相同所有数字都会发生,所以让我们直接看到数字4 ,它有多个条目,如下所示,
[ 4 , 5], [ 4 , 3] [ 4 , 5], [ 4 , 3]
then sort these entries by index,然后按索引对这些条目进行排序,

[ 4 , 3], [ 4 , 5] [ 4 , 3], [ 4 , 5]
here again indexes are not adjacent indexes 3 + 1 != 5 , and count of non adjacent number is two .这里再次索引不是相邻索引3 + 1 != 5 ,并且非相邻数的计数是two Same process will be applied on all numbers and final answer will be max non adjacent number count = 2相同的过程将应用于所有数字,最终答案将是最大非相邻数字count = 2

For other example of array [4, 4, 4, 4, 4] final number and index array of it will be,对于数组[4, 4, 4, 4, 4]的其他示例,它的最终编号和索引数组将是,

[ 4 , 0], [ 4 , 1], [ 4 , 2], [ 4 , 3], [ 4 , 4] [ 4 , 0], [ 4 , 1], [ 4 , 2], [ 4 , 3], [ 4 , 4]
And as you can see index 0 , 2 , 4 are not adjacent indexes and max non adjacent number count = 3如您所见,索引024不是相邻索引,最大非相邻数count = 3

#include <iostream>

#include <vector>
#include <algorithm>

using std::cout;

std::size_t countNonAdjacentEntries(std::vector<std::pair<int, std::size_t>>::const_iterator firstIt,
                                    std::vector<std::pair<int, std::size_t>>::const_iterator lastIt){


    std::size_t count = 0;

    for(std::vector<std::pair<int, std::size_t>>::const_iterator preIt = firstIt, it = preIt + 1; lastIt != it;){

        if(preIt->second + 1 != it->second){

            ++count;

            preIt = it;
            ++it;
        }
        else{
            ++it;
        }
    }

    ++count;
    return count;
}

std::size_t maxNonAdjacentNumber(const std::vector<int>& numbers){

    std::vector<std::pair<int, std::size_t>> numAndIndex;
    numAndIndex.reserve(numbers.size());

    for(std::vector<int>::size_type i = 0, numbersCount = numbers.size(); i < numbersCount; ++i){

        numAndIndex.emplace_back(numbers[i], i);
    }

    std::sort(numAndIndex.begin(), numAndIndex.end(),
              [](const std::pair<int, std::size_t>& a, const std::pair<int, std::size_t>& b){
        return a.first < b.first;});

    std::size_t count = 0;

    for(std::vector<std::pair<int, std::size_t>>::const_iterator it = numAndIndex.cbegin(), endIt = numAndIndex.cend();
        endIt != it; ){

        std::vector<std::pair<int, std::size_t>>::const_iterator upBoundIt = std::upper_bound( it + 1, endIt, it->first,
                    [](int val, const std::pair<int, std::size_t>& ele){return val < ele.first;});

        if(upBoundIt - it > 1){

            std::sort(numAndIndex.begin(), numAndIndex.end(),
                      [](const std::pair<int, std::size_t>& a, const std::pair<int, std::size_t>& b){
                return a.second < b.second;});

            count = std::max(count, countNonAdjacentEntries(it, upBoundIt));
            it = upBoundIt;
        }
        else{
            ++it;
        }
    }

    return count;
}

int main(){

    cout<< "[9, 2, 3, 4, 0, 4, 5, 6, 0, 8] => "<< maxNonAdjacentNumber({9, 2, 3, 4, 0, 4, 5, 6, 0, 8})<< '\n';
    cout<< "[4, 4, 4, 4, 4] => "<< maxNonAdjacentNumber({4, 4, 4, 4, 4})<< '\n';
}

Output Output

[9, 2, 3, 4, 0, 4, 5, 6, 0, 8] => 2
[4, 4, 4, 4, 4] => 3

unique to remove duplicates, sort to clump remaining, then find longest run.独特的删除重复,排序剩余的丛,然后找到最长的运行。

template<class T, class A>
std::optional<T> most_runs_of( std::vector<T, A> r ) {
  if (r.empty()) return std::nullopt;
  r.erase( std::unique( begin(r), end(r) ), end(r) );
  std::sort( begin(r), end(r) );
  T winner = r.front();
  std::size_t winner_count = 0;
  T const* cur = nullptr;
  std::size_t cur_count = 0;
  for (T const& e:r) {
    if (e == winner)
    {
      ++winner_count;
      continue;
    }
    if (cur && *cur==e) {
      ++cur_count;
      if (cur_count > winner_count) {
        winner = e;
        winner_count = cur_count;
        cur = nullptr;
        continue;
      }
    }
    cur = std::addressof(e);
    cur_count = 1;
  }
  return winner;
}

This copies the std::vector and does it in-place in the copy in O(nlgn) and O(n) space.这会复制std::vector并在 O(nlgn) 和 O(n) 空间的副本中就地执行它。

If you don't need the std::vector after you call the above, std::move it into the algorithm.如果您在调用上述内容后不需要std::vector ,请将其std::move到算法中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM