Поиск нечетного числа в массиве
Я пытаюсь решить проблему, где мне дали массива, например [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.