移动零:Java解法详解
来源:283. 移动零
目录
题目
给定一个数组 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
详解
方法一:双指针(官方解法)
该方法的核心在于思维训练,建议深入学习掌握。
思路及解法
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。
右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
注意到以下性质:
左指针左边均为非零数;
右指针左边直到左指针处均为零。
因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
代码
class Solution {
/**
* 将数组中的所有零元素移动到数组的末尾,同时保持非零元素的相对顺序。
*
* @param nums 输入的整数数组
*/
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++; // 右指针右移,继续遍历数组
}
}
/**
* 交换数组中两个指定位置的元素。
*
* @param nums 输入的整数数组
* @param left 左侧元素的索引
* @param right 右侧元素的索引
*/
public void swap(int[] nums, int left, int right) {
int temp = nums[left]; // 临时变量保存左指针位置的元素
nums[left] = nums[right]; // 将右指针位置的元素赋值给左指针位置
nums[right] = temp; // 将临时保存的元素赋值给右指针位置
}
}
代码说明
moveZeroes
方法通过双指针技术遍历数组,将非零元素逐步移动到数组的前端。swap
方法用于交换数组中两个指定位置的元素,这里用于将非零元素交换到前面来。- 使用两个指针
left
和right
,right
指针遍历整个数组,而left
指针用于标记下一个非零元素应放置的位置。
方法二(简单做法)
思路及解法
我们可以通过计数器记录零元素的数量。遇到非零元素时直接存入数组,遍历结束后在数组末尾补上相应数量的零即可。
代码
import java.util.Arrays;
class Solution {
public void moveZeroes(int[] nums) {
// int pc = 0;
// int ac = 0;
// //new一个int数组
// int[] num2 = new int[nums.length];
// for (int num : nums) {
// if (num != 0) {
// //将不为0的元素添加到num2
// num2[pc] = num;
// pc++;
// }
// }
// //num2的值给num
// for (int num : num2) {
// nums[ac] = num;
// ac++;
// }
int pc = 0;
for(int num : nums){
if(num != 0){
nums[pc++] = num;
}
}
for (int i = pc; i < nums.length; i++ ){
nums[i] = 0;
}
}
}
//测试用例
public class Main {
public static void main(String[] args) {
int[] nums = {0, 1, 0, 3, 12};
Solution solution = new Solution();
solution.moveZeroes(nums);
//输出nums数组
String result = Arrays.toString(nums); // 使用Arrays.toString()方法
System.out.println(result);
}
}
知识点:增强for
基本语法
增强的 for
循环的语法如下:
for (元素类型 元素变量名 : 数组或集合) {
// 循环体
}
1. 遍历数组
增强的 for
循环可以非常简洁地遍历数组中的所有元素,而不需要手动处理索引和数组长度。例如:
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
2. 遍历集合
增强的 for
循环同样适用于遍历集合(如 List
、Set
等)。例如:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
3. 只读循环
增强的 for
循环是只读的,这意味着你不能通过循环修改数组或集合中的元素。如果你需要修改元素,应使用传统的 for
循环或迭代器。
4. 无法获取索引
增强的 for
循环不提供对当前元素索引的直接访问。如果需要索引,应使用传统的 for
循环。
5. 性能考虑
增强的 for
循环在大多数情况下性能与传统的 for
循环相似,因为它在内部使用迭代器进行遍历。
6. 适用范围
增强的 for
循环可以用于任何实现了 Iterable
接口的对象,包括所有集合类。
示例代码
以下是一个完整的示例,展示了如何使用增强的 for
循环遍历数组和集合:
public class EnhancedForLoopExample {
public static void main(String[] args) {
// 遍历数组
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
// 遍历集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
}
}
收起
通过这些知识点,你可以更好地理解和使用增强的 for
循环来简化代码,提高可读性。