目录
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?
我们可以统计一下nums各个位置前面分别有多少0,有n个0就把这个位置上的数向前移动n位 ,再把数组末尾空缺的位置补上0即可。
- class Solution {
- public void moveZeroes(int[] nums) {
-
- int len = nums.length;
- int []ling = new int[len]; //记录第i位前面有几个0
- int sum = 0; //记录一共有几个0
-
- //记录第i位前面有几个0
- for(int i=0; i<len; i++){
- if(nums[i] == 0){
- ling[i] = -1;
- sum++;
- } else {
- ling[i] = sum;
- }
- }
- //前面有几个0就向前移动几位
- for(int i=0; i<len; i++){
- if(nums[i] != 0){
- nums[i-ling[i]] = nums[i];
- }
- }
- //把后面补上0
- for(int i=len-1; i>=len-sum; i--){
- nums[i] = 0;
- }
- }
- }
时间复杂度: O(N)
空间复杂度: O(N)
时间复杂度已经足够优秀了,但是操作次数过多;空间复杂度还不够完美,能否减少空间的使用呢?
这就需要用到双指针了。
1、开始时两指针同时在最左边,然后左右指针同时右移去找零。
2、当左指针指零时,右指针右移去找非零。
3、当找到非零时,交换;
4、左右指针再同时右移去找零(重复1,2,3直到右指针达到末尾)
- class Solution {
- public void moveZeroes(int[] nums) {
- int n = nums.length, left = 0, right = 0;
- while (right<n) {
- //如果左指针指非零,无需交换,双指针后移
- while(right<n && nums[left]!=0){
- left++;
- right++;
- }
- //如果左指针指零,那么右指针后移去找非零,然后交换
- while(right<n && nums[right]==0){
- right++;
- }
- if(right<n){
- swap(nums, left, right);
- //交换完之后,双指针后移一位
- left++;
- right++;
- }
- }
- }
-
- public void swap(int[] nums, int left, int right) {
- int temp = nums[left];
- nums[left] = nums[right];
- nums[right] = temp;
- }
-
- }
可以简化一下代码:
- class Solution {
- public void moveZeroes(int[] nums) {
- int n = nums.length, left = 0, right = 0;
- while (right < n) {
- if (nums[right] != 0) {
- swap(nums, left, right);
- left++;
- }
- right++;
- }
- }
-
- //交换
- public void swap(int[] nums, int left, int right) {
- int temp = nums[left];
- nums[left] = nums[right];
- nums[right] = temp;
- }
- }
时间复杂度: O(N)
空间复杂度: O(1)