Hello_Motty

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

  Given an array and a value, remove all instances of that value in place and return the new length.Do not allocate extra space for another array, you must do this in place with constant memory. The order of elements can be changed. It doesn't matter what you leave beyond the new length.

Example:
  Given input array nums = [3,2,2,3]val = 3  Your function should return length = 2, with the first two elements of nums being 2.

题意:给出一个数组和一个值,原地挖掉数组中对应的值(以下以val代替),不允许使用新数组即空间复杂度O(1),返回长度并返回去掉val后的数组

错误思路:

  只看到了返回值,我开始的时候真的只看到了返回值。然后根本没去除掉val。所以最快去掉所有val并返回长度才是关键。

基本思路:

  如果不会特别的思路,就用一种比较慢的想法做也可以,每遇到一个val就把后面所有元素向前移动一位把val覆盖掉,并且让数组长度减1,如果val在最后一位那么数组长度直接减1。最坏情况时间复杂度O(n*n)。因为数据量比较小所以即使反复的对数据进行操作也不会特别慢。

 1 int removeElement(int* nums, int numsSize, int val) {
 2     int i=0, j =i+1;
 3     for(i=0;i<numsSize; ++i){
 4         if(nums[i] == val ){
 5             if(i<numsSize - 1){
 6                 for(j = i+1;j<numsSize;++j){
 7                     nums[j-1] = nums[j];
 8                 }
 9                 --i;
10             }
11             --numsSize;
12         }
13     }
14     return numsSize;
15 }

  稍微优化一下,其实我们根本不在乎数组中除了val以外数字的顺序,所以我们可以遇到val时就把最后一个元素赋值给当前元素,然后数组长度减1。最后返回数组长度即可。最差时间复杂度O(n)。

 1 int removeElement(int* nums, int numsSize, int val) {   
 2     int i=0;
 3     while(i<numsSize){
 4         if(nums[i] == val){
 5             if(i != numsSize - 1){
 6                 nums[i] = nums[numsSize - 1];
 7             }
 8             --numsSize;
 9         }else{
10             ++i;
11         }
12     }
13     return numsSize;
14 }

  再优化一下,第三种方法,不见得比第二种好,但是代码至少看上去更短。

1 class Solution {
2 public:
3     int removeElement(vector<int>& nums, int val) {
4         nums.erase(remove(nums.begin(),nums.end(),val),nums.end());
5         return nums.size();
6     }
7 };

  使用了STL中的erase(remove())组合。底层实现其实有点像第二种,大致是如下,比如我们想删除容器中的99:

    

  如果我们把remove的返回值存放在一个叫做newEnd的新迭代器中,那么remove后应该就是这样的:

    

  而中间的过程,3个99被放在了尾部,用问号代替?然而实际上里面的元素是这样的:

    

  真实的移动情况是这样的:

    

  找到一个待覆盖位置,用后面第一个非val元素覆盖,则该位置变为新待覆盖位置,然后重复前面操作,直到最后一个元素,返回第一个待覆盖元素位置。

  这样做的好处在于不会改变数组中其他元素顺序并且时间复杂度较第一种方法要低(因为每次只查找少于n-i个元素,移动其中1个元素)。

  实现代码略。

 

posted on 2017-09-22 20:59  Hello_Motty  阅读(235)  评论(0编辑  收藏  举报