Как проверить есть ли элемент, при удалении которого все элементы массива будут равны?
У нас есть массив целых чисел.
Необходимо выяснить, есть ли элемент, при удалении которого все элементы массива будут равны.
в случае одного элемента вернуть "true" - x= [1, 1, -2, 1, 1]
если нет, или если их несколько, вернуть «false» -
x=[1, 2, 1, 1, 5]
x=[1, 1, 1, 1, 1]
Ответы (5 шт):
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. Немного перемудрил с алгоритмом, идея Грундия с размером сета вполне хорошое упрощение моего текущего алгоритма.
// массив, подходящий под условия – это массив с 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
Если при удалении одного элемента, остальные остаются равными, значит, что в массиве изначально было два уникальных элемента. Именно это и достаточно проверить.
Для поиска уникальных элементов можно использовать 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]));
Метод с использованием алгоритма большинства голосов Бойера — Мура.
Алгоритм линейный, используется обычно для нахождения доминирующего элемента с количеством не менее длины половины массива. Очередной элемент старается вытеснить текущего лидера, если он с ним не совпадает, либо укрепляет его позицию, если совпадает. В конце остаётся элемент с 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]))
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]))