• 283. Move Zeroes【easy】


    283. Move Zeroes【easy】

    Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

    For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

    Note:

    1. You must do this in-place without making a copy of the array.
    2. Minimize the total number of operations.

    Credits:
    Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.

    解法一:

     1 class Solution {
     2 public:
     3     void moveZeroes(vector<int>& nums) {
     4         int i = 0, j = 0;
     5         while (i < nums.size()) {
     6             if (nums[i] != 0) {
     7                 nums[j++] = nums[i++];
     8             }
     9             else
    10             {
    11                 ++i;
    12             }
    13         }
    14         
    15         while (j < nums.size()) {
    16             nums[j++] = 0;
    17         }  
    18     }
    19 };

    双指针

    解法二:

    This is a 2 pointer approach. The fast pointer which is denoted by variable "cur" does the job of processing new elements. If the newly found element is not a 0, we record it just after the last found non-0 element. The position of last found non-0 element is denoted by the slow pointer "lastNonZeroFoundAt" variable. As we keep finding new non-0 elements, we just overwrite them at the "lastNonZeroFoundAt + 1" 'th index. This overwrite will not result in any loss of data because we already processed what was there(if it were non-0,it already is now written at it's corresponding index,or if it were 0 it will be handled later in time).

    After the "cur" index reaches the end of array, we now know that all the non-0 elements have been moved to beginning of array in their original order. Now comes the time to fulfil other requirement, "Move all 0's to the end". We now simply need to fill all the indexes after the "lastNonZeroFoundAt" index with 0.

     1 void moveZeroes(vector<int>& nums) {
     2     int lastNonZeroFoundAt = 0;
     3     // If the current element is not 0, then we need to
     4     // append it just in front of last non 0 element we found. 
     5     for (int i = 0; i < nums.size(); i++) {
     6         if (nums[i] != 0) {
     7             nums[lastNonZeroFoundAt++] = nums[i];
     8         }
     9     }
    10     // After we have finished processing new elements,
    11     // all the non-zero elements are already at beginning of array.
    12     // We just need to fill remaining array with 0's.
    13     for (int i = lastNonZeroFoundAt; i < nums.size(); i++) {
    14         nums[i] = 0;
    15     }
    16 }

    Complexity Analysis

    Space Complexity : O(1)O(1). Only constant space is used.

    Time Complexity: O(n)O(n). However, the total number of operations are still sub-optimal. The total operations (array writes) that code does is nn (Total number of elements).

    解法三:

    The total number of operations of the previous approach is sub-optimal. For example, the array which has all (except last) leading zeroes: [0, 0, 0, ..., 0, 1].How many write operations to the array? For the previous approach, it writes 0's n-1n1 times, which is not necessary. We could have instead written just once. How? ..... By only fixing the non-0 element,i.e., 1.

    The optimal approach is again a subtle extension of above solution. A simple realization is if the current element is non-0, its' correct position can at best be it's current position or a position earlier. If it's the latter one, the current position will be eventually occupied by a non-0 ,or a 0, which lies at a index greater than 'cur' index. We fill the current position by 0 right away,so that unlike the previous solution, we don't need to come back here in next iteration.

    In other words, the code will maintain the following invariant:

    1. All elements before the slow pointer (lastNonZeroFoundAt) are non-zeroes.

    2. All elements between the current and slow pointer are zeroes.

    Therefore, when we encounter a non-zero element, we need to swap elements pointed by current and slow pointer, then advance both pointers. If it's zero element, we just advance current pointer.

    With this invariant in-place, it's easy to see that the algorithm will work.

    1 void moveZeroes(vector<int>& nums) {
    2     for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
    3         if (nums[cur] != 0) {
    4             swap(nums[lastNonZeroFoundAt++], nums[cur]);
    5         }
    6     }
    7 }

    Complexity Analysis

    Space Complexity : O(1)O(1). Only constant space is used.

    Time Complexity: O(n)O(n). However, the total number of operations are optimal. The total operations (array writes) that code does is Number of non-0 elements.This gives us a much better best-case (when most of the elements are 0) complexity than last solution. However, the worst-case (when all elements are non-0) complexity for both the algorithms is same.

    上面解法仍有优化空间,对于下标不同的时候才交换

     1 class Solution {
     2 public:
     3     void moveZeroes(vector<int>& nums) {
     4         for (int i = 0, j = 0; i < nums.size(); ++i) {
     5             if (nums[i] != 0) {
     6                 if (i != j) {
     7                     swap(nums[j], nums[i]);
     8                 }
     9                 ++j;
    10             }
    11         }
    12     }
    13 };

    解法二、三均参考自solution

  • 相关阅读:
    多线程设计的要素—任务线程确定
    https://www.neroxie.com/2019/01/22/深入理解GCD之dispatch-group/
    性能、指标、监控、数据大盘
    iOS PhotoKit 笔记
    多线程的核心问题是控制共享变量的无序访问(读写)
    objective-c arc -对象、变量、变量修饰符、赋值
    大幅降低存储成本,Elasticsearch可搜索快照是如何办到的?
    压测利器:TarsBenchmark正确打开方式
    跨国合作:Serverless Components 在腾讯云的落地和实践
    前端视角谈物联网三部曲:连接智能、交互智能、数据智能
  • 原文地址:https://www.cnblogs.com/abc-begin/p/7623618.html
Copyright © 2020-2023  润新知