Поиск нечетного числа в массиве

Я пытаюсь решить проблему, где мне дали массива, например [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10] где все числа повторяются дважды, кроме одного номера, и мне нужно вернуться в номер, который не дублируется.

Я пытаюсь сделать это так:

def findNumber(self, nums):

    if (len(nums) == 1):
        return nums[0]

    nums_copy = nums[:]

    for i in nums:
        nums_copy.remove(i)

        if i not in nums:
            return i
        else:
            nums_copy.remove(i)

однако, когда он достигает оператора else, возникает следующая ошибка:

ValueError: список.удалить(x): x не в списке

это происходит когда i находится в nums_copy, Так что я не понимаю, почему эта ошибка возникает в этой ситуации?

8 ответов


уже nums_copy.remove(i) Так нельзя nums_copy.remove(i) еще раз

вы могли бы сделать:

a = [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10]

def get_single_instance(array):
  d = {}

  for item in a:
    if item not in d:
      d[item] = 1
    else:
      d[item] += 1

  print d

  for k, v in d.iteritems():
    if v == 1:
      return k

print get_single_instance(a)

результат: 9


более простой (и более эффективный) способ сделать это, чем ваш первоначальный подход с Counter


лучший алгоритм-использовать XOR для поиска нечетного числа.

def find_number(nums):
    s = 0 
    for n in nums:
        s ^= n 
    return s 


a = [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10] 
print(find_number(a))

попробуйте этот список понимания. Он проходит через каждый элемент и проверяет, дублируется ли он, а если нет, он позволяет ему оставаться в новом списке. Затем он получает нулевой элемент нового списка:

a=[0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10]
[e for e in a if a.count(e)==1][0]

Если массив отсортирован, мы можем найти ответ в O(log n) время и O(1) дополнительное пространство. Учтите, что повторяющиеся пары чисел начинаются с нечетных или четных индексов в зависимости от того, где находится один элемент:

              0  1  2  3  4  5  6  7  8  9   10
             [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10]
even indexes: x     x     x     x
odd indexes:                             x

search:                      ^  (0 + 11) / 2 = 5
                         [2, 2] pair starting on even index
                                so the singleton must be ahead

                                      ^  (6 + 11) / 2 = 8
                                     [9] singleton found in two steps!

Это очень длинный метод делать вещи. Как было предложено, вы можете использовать nums_copy.remove(i) или вы можете реализовать это гораздо проще, используя count():

def findNumber(self, nums):

    for i in nums:

        val = nums.count(i)

        if val == 1:
            return i

это вернет единственное число. Этот метод хорош до тех пор, пока у вас нет нескольких значений, если это так, он вернет только последнее. В противном случае вы можете вернуть список, в котором будет храниться несколько значений:

def findNumber(self, nums):
    values = []
    for i in nums:

        val = nums.count(i)

        if val == 1:
            values.append(i)

    return values

предполагая отсортированную итерацию (в противном случае сортируйте ее), вот первое появление пары, не повторяющейся:

import more_itertools as mit


iterable = [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10] 
next(x for x, y in mit.windowed(iterable, n=2, step=2) if x != y)
# 9

альтернативный способ создания непересекающихся пар:

next(x for x, y in mit.sliced(iterable, 2) if x != y)
# 9

more_itertools является сторонней библиотекой,> pip install more_itertools.


для тех, кто работает с NumPy, это должно быть конкурентоспособным по скорости с другими ответами здесь:

>>> def get_single_instance_np(arr: np.ndarray):
...     return np.asscalar(arr[np.bincount(arr) == 1])

>>> print(get_single_instance(a))
9

Это просто возвращает элементы, для которых их количество равно 1.