Как проверить есть ли элемент, при удалении которого все элементы массива будут равны?

У нас есть массив целых чисел.

Необходимо выяснить, есть ли элемент, при удалении которого все элементы массива будут равны.

в случае одного элемента вернуть "true" - x= [1, 1, -2, 1, 1]

если нет, или если их несколько, вернуть «false» -

x=[1, 2, 1, 1, 5] 
x=[1, 1, 1, 1, 1]

Ответы (5 шт):

Автор решения: entithat

function foo(arr) {
  return arr.map((e, i, a) => [...new Set([...a].filter((_, j) => j !== i))].join ``.length === 1).filter(Boolean).length === 1;
}

console.log(foo([1, 1, 2, 1, 1])); // T
console.log(foo([1, 1, 2, 5, 1, 1])); // F
console.log(foo([1, 1, 1, 1, 1])); // F

P.S. Немного перемудрил с алгоритмом, идея Грундия с размером сета вполне хорошое упрощение моего текущего алгоритма.

→ Ссылка
Автор решения: Aleksandr Belous
// массив, подходящий под условия – это массив с 2мя видами чисел, одно из которых уникальное и повторяется один раз, а все остальные элементы – второе число.

const isDeletable = (numbers) => {
  // дополнительная проверка - если массив состоит из 2 чисел, то он подходит.
  // Не было в условии, можете убрать. Это пограничный случай.
  if (numbers.length === 2) {
    return true;
  }

  // получаем все виды чисел
  const elements = [...new Set(numbers)];

  // если их не 2, то уже не подходит
  if (elements.length !== 2) {
    return false;
  }

  // получаем числа, которые повторяются 1 раз
  const uniqueElements = elements.filter((uniqueNumber) => {
    const all = numbers.filter((number) => number === uniqueNumber);
    return all.length === 1;
  });

  // если одно уникальное число, то массив подходит 
  return uniqueElements.length === 1;
};

console.log(isDeletable([1, 1, -2, 1, 1])); // true
console.log(isDeletable([1, 2, 1, 1, 5])); // false
console.log(isDeletable([1, 1, 1, 1, 1])); // false
console.log(isDeletable([1, 1, 2, 2, 1])); // false
console.log(isDeletable([1, 1, 2, 2, 1, 3])); // false
console.log(isDeletable([1, 1, 2, 1, 3])); // false
console.log(isDeletable([1, 2])); // true
→ Ссылка
Автор решения: Grundy

Если при удалении одного элемента, остальные остаются равными, значит, что в массиве изначально было два уникальных элемента. Именно это и достаточно проверить.

Для поиска уникальных элементов можно использовать Set.

В этом случае все сводится к проверке размера получившегося сета, с помощью свойства size

.size === 2

Пример:

function foo(arr) {
  return new Set(arr).size === 2;
}

console.log(foo([1, 1, 2, 1, 1])); // T
console.log(foo([1, 1, 2, 5, 1, 1])); // F
console.log(foo([1, 1, 1, 1, 1])); // F

Также можно обойтись простым циклом, подсчитывая уникальные элементы и прекращая его в случае если количество больше двух

function foo(arr) {
  var set = Object.create(null);
  var count = 0;
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] in set) continue;
    set[arr[i]] = true;
    count += 1;
    if (count > 2) return false;
  }
  return count === 2;
}

console.log(foo([1, 1, 2, 1, 1])); // T
console.log(foo([1, 1, 2, 5, 1, 1])); // F
console.log(foo([1, 1, 1, 1, 1])); // F


Для случая, если лишние элементы так же могут повторяться логика немного усложнится тем, что проверять нужно не только количество уникальных элементов, но и количество их повторений.

function foo(arr) {
  var set = Object.create(null);
  var count = 0;
  var firstNonUniq;
  for (var i = 0; i < arr.length; i++) {
    set[arr[i]] = (set[arr[i]] ?? 0) + 1;
    if (set[arr[i]] == 1) {
      count += 1;
      if (count > 2) return false;
    } else if (count == 1) { // сохраняем первое неуникальное значение
      firstNonUniq = arr[i];
    } else if (arr[i] !== firstNonUniq) { // если больше одного не уникального значения возвращаем false
      return false;
    }
  }
  return count === 2;
}

console.log(foo([1, 1, 2, 1, 1])); // T
console.log(foo([1, 1, 2, 5, 1, 1])); // F
console.log(foo([1, 1, 1, 1, 1])); // F
console.log(foo([1, 1, 2, 2, 1, 1]));

→ Ссылка
Автор решения: MBo

Метод с использованием алгоритма большинства голосов Бойера — Мура.

Алгоритм линейный, используется обычно для нахождения доминирующего элемента с количеством не менее длины половины массива. Очередной элемент старается вытеснить текущего лидера, если он с ним не совпадает, либо укрепляет его позицию, если совпадает. В конце остаётся элемент с count>=len/2, если такой есть. А если такого нет - в лидерах остаётся произвольный, поэтому, к сожалению, нужен второй проход для подсчёта.

(Иначе для данной задачи можно было бы сравнивать с == len-2, но это провалится на наборах типа [1,2,3])

Код на Python (тест на ideone):

def checku(a):
    c = 0
    for v in a:
        if c == 0:
            m = v
            c = 1
        else:
            c = c + (1 if m == v else -1)
    return a.count(m) == len(a) - 1
 
print(checku([1, 2]))
print(checku([1, 1, 2, 1, 1]))
print(checku([2, 1, 1, 1, 1]))
print(checku([1]))
print(checku([1, 2, 3]))
print(checku([1, 1, 2, 5, 1, 1]))
print(checku([1, 1, 1, 1, 1]))
print(checku([1, 1, 2, 2, 1]))

Перевод на js:

var print = console.log;

function checku(a) {
  var c = 0
  for (var v of a)
    if (c == 0) {
      var m = v;
      c = 1;
    } else {
      c = c + (m == v ? 1 : -1);
    }
  return a.filter(el => m == el) == a.length - 1;
}

print(checku([1, 2]))
print(checku([1, 1, 2, 1, 1]))
print(checku([2, 1, 1, 1, 1]))
print(checku([1]))
print(checku([1, 2, 3]))
print(checku([1, 1, 2, 5, 1, 1]))
print(checku([1, 1, 1, 1, 1]))
print(checku([1, 1, 2, 2, 1]))

→ Ссылка
Автор решения: Qwertiy

function check(arr) {
  switch (arr.length) {
    case 0:
      return false
    
    case 1:
      return true
    
    case 2:
      return false
      
    default:
      var [a, b, c] = arr
      var x = a === b ? a : a === c ? a : b === c ? b : undefined
      if (x === undefined) return false
      return arr.filter(y => y !== x).length === 1
  }
}

console.log(check([1, 1, 2, 1, 1]))
console.log(check([2, 1, 1, 1, 1]))
console.log(check([2, 1, 1, 1, 2]))
console.log(check([1, 2, 3, 1, 1]))
console.log(check([1, 2, 1, 4, 1]))

→ Ссылка