leetcode-283-移动零(remove zeroes)-java

题目及测试用例

package pid283;
/*移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

    必须在原数组上操作,不能拷贝额外的数组。
    尽量减少操作次数。





*/


public class main {
	
	public static void main(String[] args) {
		int[][] testTable = {{0,1,0,3,12},{1,2,3,4},{1,0,1,3,0,4,0,2,0,2},{0,6,2,7,0}};
		for (int[] ito : testTable) {
			test(ito);
		}
	}
		 
	private static void test(int[] ito) {
		Solution solution = new Solution();
		boolean rtn;
		long begin = System.currentTimeMillis();
		for (int i = 0; i < ito.length; i++) {
		    System.out.print(ito[i]+" ");		    
		}
		System.out.println();
		//开始时打印数组
		
		 solution.moveZeroes(ito);//执行程序
		long end = System.currentTimeMillis();	
		
		//System.out.println(ito + ": rtn=" + rtn);
		System.out.println(":rtn" );
		for (int i = 0; i < ito.length; i++) {
		    System.out.print(ito[i]+" ");
		}//打印结果几数组
		
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,1ms,很快)
问题的两个要求是:
将所有 0 移动到数组末尾。
所有非零元素必须保持其原始顺序。
这里很好地认识到这两个需求是相互排斥的,也就是说,你可以解决单独的子问题,然后将它们组合在一起以得到最终的解决方案。
这种方法即先满足一个需求,然后满足另一个需求。它以一种巧妙的方式做到了这一点。上述问题也可以用另一种方式描述,“将所有非 0 元素置于数组前面,保持它们的相对顺序相同”。
这是双指针的方法。由变量 “i” 表示的快速指针负责处理新元素。如果新找到的元素不是 0,我们就在最后找到的非 0 元素之后记录它。最后找到的非 0 元素的位置由慢指针 “index” 变量表示。当我们不断发现新的非 0 元素时,我们只是在 “index” 第个索引处覆盖它们。此覆盖不会导致任何数据丢失,因为我们已经处理了其中的内容(如果它是非 0 的,则它现在已经写入了相应的索引,或者如果它是 0,则稍后将进行处理)。
在 “i” 索引到达数组的末尾之后,我们现在知道所有非 0 元素都已按原始顺序移动到数组的开头。现在是时候满足其他要求了,“将所有 0 移动到末尾”。我们现在只需要在 “index” 索引之后用 0 填充所有索引。

从头向尾循环,留下一个标志记录非0的index
如果为0,则不变,向后循环
不为0,则index+1,向后循环
最后将index到length之间的全部设置为0

package pid283;

import java.util.Arrays;

public class Solution {
public void moveZeroes(int[] nums) {
		int length=nums.length;
		//下一个要设置的非0元素的位置
		int index=0;
		for(int i=0;i<length;i++){
			if(nums[i]!=0){
				nums[index++]=nums[i];				
			}
		}
		for(int i=index;i<length;i++){
			nums[i]=0;
		}		        
    }
}

解法2(别人的,最优解)
前一种方法的操作是局部优化的。例如,所有(除最后一个)前导零的数组:[0,0,0,…,0,1]。对数组执行多少写操作?对于前面的方法,它写 0 n−1n-1n−1 次,这是不必要的。我们本可以只写一次。怎么用?… 只需固定非 0 元素。
最优方法也是上述解决方案的一个细微扩展。一个简单的实现是,如果当前元素是非 0 的,那么它的正确位置最多可以是当前位置或者更早的位置。如果是后者,则当前位置最终将被非 0 或 0 占据,该非 0 或 0 位于大于 “cur” 索引的索引处。我们马上用 0 填充当前位置,这样不像以前的解决方案,我们不需要在下一个迭代中回到这里。
换句话说,代码将保持以下不变:
慢指针(lastnonzerofoundat)之前的所有元素都是非零的。
当前指针和慢速指针之间的所有元素都是零。
因此,当我们遇到一个非零元素时,我们需要交换当前指针和慢速指针指向的元素,然后前进两个指针。如果它是零元素,我们只前进当前指针。

void moveZeroes(vector<int>& nums) {
    for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
        if (nums[cur] != 0) {
            swap(nums[lastNonZeroFoundAt++], nums[cur]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值