简体   繁体   English

查找列表中出现奇数次的元素

[英]Find Elements occurring odd number of times in a list

Let's say we need to find all the elements occurring an odd number of times in a sorted list in O(N) time and O(1) space complexity.假设我们需要在 O(N) 时间和 O(1) 空间复杂度的有序列表中找到所有出现奇数次的元素。

ls = [1,2,2,3,3,3,4,5,5,6,6,6,6,6]        
output = [1,3,4,6]

We are not going to return a new list, perhaps will be overwrite the existing one我们不会返回新列表,可能会覆盖现有列表

I have an approach which uses a hashing technique, but it results in O(N) space complexity.我有一种使用散列技术的方法,但它会导致 O(N) 空间复杂度。

I have tried bitwise manipulation using XOR, but I am not able to solve the question.我已经尝试使用 XOR 进行按位操作,但我无法解决这个问题。

Iterate through the list, counting cases where the present item is the same as the previous one, and overwriting towards the start of the list when it is different and the count is an odd number.遍历列表,计算当前项目与前一个项目相同的情况,并在不同且计数为奇数时覆盖列表的开头。

This solution overwrites the existing list rather than allocating a new one, and has O(N) time complexity.此解决方案覆盖现有列表而不是分配新列表,并且具有 O(N) 时间复杂度。 Because the new list will be shorter, we have to pop the remaining items from the end of it.因为新列表会更短,所以我们必须从它的末尾pop剩余的项目。 (We would normally splice using ls = ls[position:] but that would assign a new list, which isn't allowed.) (我们通常会使用ls = ls[position:]进行拼接,但这会分配一个新列表,这是不允许的。)

def keep_odd_elements(ls):
    count = 0
    write_position = 0
    previous = object()
    for item in ls:
        if item == previous:
            count += 1
        else:
            # Write the odd-counted numbers towards the start of the list
            if count % 2:
                ls[write_position] = previous
                write_position += 1
            count = 1
        previous = item
    if count % 2:
        ls[write_position] = previous
        write_position += 1
    # Remove the leftover items at the end of the list
    for i in range(write_position, len(ls)):
        ls.pop()
    
ls = [1,2,2,3,3,3,4,5,5,6,6,6,6,6]
keep_odd_elements(ls)
print(ls)   # [1, 3, 4, 6]

If we remove the requirement not to allocate a new list, then we can write this much more elegantly:如果我们删除不分配新列表的要求,那么我们可以更优雅地编写:

def get_odd_elements(ls):
    count = 0
    for previous, item in zip([object()] + ls, ls + [object()]):
        if item == previous:
            count += 1
        else:
            if count % 2:
                yield previous
            count = 1

print(list(get_odd_elements([1,2,2,3,3,3,4,5,5,6,6,6,6,6])))

This is C++ code that runs in O(n) and use O(1) auxiliary memory.这是在 O(n) 中运行并使用 O(1) 辅助 memory 的 C++ 代码。

The idea behind this code is very simple, we start from left and counting number of occurrence of a number x until we arrive to a number y that not equal x , because of our input is sorted it guarantee that x never appear after y .这段代码背后的想法很简单,我们从左边开始计算数字x的出现次数,直到我们到达不等于x的数字y ,因为我们的输入是排序的,它保证x永远不会出现在y之后。 So it's sufficient to check if number of occurrence of x be odd.因此,检查x的出现次数是否为奇数就足够了。

Note that, if the array is not sorted it's provable that, you can't do better than O(nlogn)请注意,如果数组未排序,则可以证明,你不能做得比 O(nlogn)

 //Find odd numbers in given sorted list

#include <stdio.h>

int main(){
    
  int ArrayLength;
  scanf("%d",&ArrayLength);
  int array[ArrayLength];
  

  //Read input sorted array
  for ( int i = 0; i < ArrayLength; i++)
       scanf("%d",&array[i]);
       

  // Find numbers with odd occurrence 
  int PreviousLocalOdd=array[0];
  int LocalOdd=1;
  for ( int i = 1; i < ArrayLength; i++)
    {

        if (array[i]==PreviousLocalOdd)
            LocalOdd++;
        
        if(array[i]!= PreviousLocalOdd)    
          {  
                if(LocalOdd % 2==1)
                    printf("%d",array[i-1]);
            LocalOdd=1;
            PreviousLocalOdd=array[i];
          }
     
    }
       if(LocalOdd % 2==1)
        printf("%d ",array[ArrayLength-1]);


return 0;
}    

To return an array without creating a new one in the function we can use two ways:要返回一个数组而不在 function 中创建一个新数组,我们可以使用两种方法:

  1. Add the answer to the existing array then delete the array elements a the end and return only the extra added answer values.将答案添加到现有数组中,然后在末尾删除数组元素并仅返回额外添加的答案值。

Cons: Manipulating the given array is not always recommended as the function could be used in other places like a result comparing function, in which case this would fail.缺点:并不总是建议操作给定的数组,因为 function 可以在其他地方使用,例如比较 function 的结果,在这种情况下会失败。

  1. To send the address of a blank array from the mail itself.从邮件本身发送一个空白数组的地址。 and add elements to it by reference.并通过引用向其中添加元素。 if we are not solving a prototype given function, we can easily make this addition to not create any extra space in the function itself如果我们不解决给定 function 的原型,我们可以轻松地进行此添加,以免在 function 本身中创建任何额外空间
  • If the elements are always <= n(size of the array) and positive and not in sorted order, you can change the value at any index.如果元素总是 <= n(数组的大小) 且为正且未按排序顺序,则可以更改任何索引处的值。 At the end loop through the array again and check the values which are negative.最后再次遍历数组并检查是否为负值。 Then the positions can be added to answer array.然后可以将位置添加到答案数组中。
    for(int i=0; i<arr.size(); i++){
       currElement = mod(arr[i]);
       arr[currElement] = arr[currElement]*-1;
    }
    for(int i=0; i<arr.size(); i++){
       if(arr[i]<0){
          ans.push_back(mod(arr[i]));
       }
    }
  • If they are in sorted order, while looping itself you can check if the max occurrence of a number is odd(by adjacent comparison) then add them to final answer.如果它们按排序顺序排列,则在循环自身时,您可以检查数字的最大出现是否为奇数(通过相邻比较),然后将它们添加到最终答案中。
    prev = -1;
    count= 0;
    for(int i=0; i<arr.size(); i++){
       if(arr[i]==prev){
           count++;
       }else{
          if(count%2!=0)
             ans.push_back(prev);
          count=1;
          prev=arr[i];
       }
    }

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

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