Учитывая массив и значение, удалите все экземпляры этого значения на месте и верните новую длину

#javascript #arrays

#javascript #массивы

Вопрос:

Это не дубликат, поскольку я не ищу ответ на конкретную проблему, я хочу понять, почему мой ответ на проблему не удается.

Я пытаюсь решить проблему с LeetCode, и функции, которые я создаю, дают правильные результаты в Chrome DevTools, но когда я отправляю их на веб-сайт, они терпят неудачу.

Я хочу понять, почему они терпят неудачу и / или не принимаются.

Пример 1:

 Given nums = [3,2,2,3], val = 3,

Your function should return length = 2, with the first two elements of nums being 2.

It doesn't matter what you leave beyond the returned length.
  

Пример 2:

 Given nums = [0,1,2,2,3,0,4,2], val = 2,

Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.

Note that the order of those five elements can be arbitrary.

It doesn't matter what values are set beyond the returned length.
  

Мои предоставленные ответы:

 var removeElement = function(nums, val) {
    return nums.filter(e => e !== val).length;
};
  

и

 var removeElement = function(nums, val) {
    for (i = 0; i < nums.length; i  = 1) {
        if (nums[i] === val) {
            nums.splice(i, 1)
        }
    }
    return nums;
};
  

Рабочий ответ, основанный на решениях:

 var removeElement = function(nums, val) {
    for (i = nums.length; i >= 0; i-= 1) {
        if (nums[i] === val) {
            nums.splice(i, 1);
        }
    }
    return nums.length;
};
  

Комментарии:

1. в первом предоставленном ответе вы не меняете значения на месте, во втором вы не возвращаете новую длину

2. «Не имеет значения, какие значения установлены за пределами возвращаемой длины». эта часть нуждается в пояснениях. Может ли ваш массив выглядеть так [ 2, 2, 3, 3] после, а затем вы возвращаете length = 2?

3. @Cid во втором ответе была опечатка, я забыл указать длину. Я возвращал только массив, чтобы просмотреть его содержимое во время отладки.

Ответ №1:

Ваше первое решение завершается неудачей, потому что вы не удаляете элементы «на месте». В настоящее время ваш исходный массив остается неизмененным, и вместо этого вы возвращаете совершенно новый массив (поскольку .filter() создает и возвращает этот новый массив).

В вашем втором решении вы не учитываете, что происходит, когда вы удаляете элемент из вашего массива. Фактически, ваше второе решение не работает (например, удаление 3 из [1, 2, 3, 3, 4] ). Причина этого в том, что при удалении элемента из вашего массива индексы в массиве будут смещаться. Например, если вы удалите элемент, когда i есть 2 , то элемент, который ранее был с индексом 3, переместится в индекс 2 после удаления, то же самое со всеми другими индексами, превышающими 2. В результате, при увеличении i на 3 значение, которое сдвинулось до индекса 2, будет пропущено.

Наглядный пример приведенного выше:

 removing = 3
i = 2
       i
 0  1  2  3  4
[1, 2, 3, 3, 4]
  

После удаления ваш массив:

  0  1  2  3
[1, 2, 3, 4]
  

Затем вы переходите к следующей итерации, так что i увеличивается до 3:

 removing = 3
i = 3
          i
 0  1  2  3
[1, 2, 3, 4]
       ^--- Skipped!
  

Еще одна небольшая проблема с вашим последним решением заключается в том, что вы должны возвращать длину массива, а не сам массив.

Ответ №2:

Первый подход не изменяет данный массив.

Ваш второй подход не удаляет все ненужные элементы,

 [0, 1, 2, 3, 0, 4]
  

потому что при удалении элемента вы получаете следующее значение с тем же индексом, но увеличиваете индекс.

Вы могли бы выполнить цикл с конца, чтобы избежать этого.

 const
    nums = [0, 1, 2, 2, 3, 0, 4, 2],
    removeElement = function(nums, val) {
        for (i = nums.length - 1; i >= 0; i--) {
            if (nums[i] === val) nums.splice(i, 1);
        }
        return nums.length;
    };
    
console.log(removeElement(nums, 2));
console.log(nums);  

Ответ №3:

  1. Первый подход заключается в создании нового массива вместо изменения исходного массива.
  2. Второй подход заключается в изменении массива во время выполнения цикла, поэтому цикл будет непоследовательным.

Вы можете использовать функцию Array.prototype.reduce для подсчета значений, отличных от переменной val .

 const nums = [0, 1, 2, 2, 3, 0, 4, 2],
      val = 2,
      removeElement = nums.reduce((a, n) => a   Boolean(n !== val), 0);
    
console.log(removeElement);  

Если вы хотите мутировать, вы можете изменить массив на месте в функции следующим образом

 const arr = [0, 1, 2, 2, 3, 0, 4, 2],
      removeElement = function(nums, val) {
        let desiredValues = nums.filter(n => n !== val);

        nums.length = 0;
        nums.splice(0, 0, ...desiredValues);
      };
      
removeElement(arr, 2);
console.log(arr);  

Ответ №4:

Вы можете использовать .indexOf() :

 var nums = [0, 1, 2, 2, 3, 0, 4, 2];

var removeElement = function(nums, val) {
    while ((i = nums.indexOf(val)) != -1) {
        nums.splice(i, 1);
    }
    return nums.length;
};
console.log(removeElement(nums, 2));
console.log(nums);  

Другое решение может использовать двойные индексы:

 const nums = [0, 1, 2, 2, 3, 0, 4, 2];

const removeElement = function(nums, val) {
    for(i=0, j=nums.length-1; i<j;) {
        while(nums[i] != val) {
            i  ;
        }
        while(nums[j] == val) {
            j--;
        }
        if (i<j) {
            nums[i] = nums[j];
            nums[j] = val;
        }
    }
    nums.length = i;
    return nums.length;
};


console.log(removeElement(nums, 2));
console.log(nums);