27. 移除元素
解法一:暴力解法
- 需要记录当前数组中的元素个数
curLength
- 用一个指针
i
从前向后遍历nums
数组:- 如果遇到等于
val
的元素就原地删除(剩余元素前移),并将curLength
减一。注意删除以后指针i
不需要向后移动。 - 如果遇到不等于
val
的元素则不做额外处理,将指针i
后移一位,继续遍历数组中的下一个元素。 - 如果数组中没有剩余元素了(
i == curLength
)就结束遍历。
- 如果遇到等于
public int removeElement(int[] nums, int val) {
int curLength = nums.length; // 记录当前数组中的元素个数
int i = 0; // 用于遍历数组的指针
while(i < curLength){
if(nums[i] == val){
// 原地删除位置i的元素(剩余元素前移)
for(int j=i+1; j<curLength; j++){
nums[j-1] = nums[j];
}
// 更新数组元素个数
curLength--;
}else{
// 指针后移,准备遍历下一个元素
i++;
}
}
return curLength;
}
解法二:双指针——左右指针分区
根据初步思路写出代码:
public int removeElement(int[] nums, int val) {
if(nums.length == 0) return 0;
// 初始化left和right指针
int left = 0, right = nums.length-1;
while(true){
// a. 移动left和right指针
while(nums[left] != val){
left++;
if(left >= nums.length){
break;
}
}
while(nums[right] == val){
right--;
if(right < 0){
break;
}
}
// b. 交换left和right指向的元素
nums[left] = nums[right];
nums[right] = val;
// c. 准备进行下一轮迭代
left++;
right--;
}
}
在之前的代码中加入迭代终止条件,以及函数返回值:
public int removeElement(int[] nums, int val) {
if(nums.length == 0) return 0;
// 初始化left和right指针
int left = 0, right = nums.length-1;
while(true){
// a. 移动left和right指针
while(nums[left] != val){
left++;
if(left >= nums.length){
break;
}
}
while(nums[right] == val){
right--;
if(right < 0){
break;
}
}
// 迭代终止条件
if(left > right){
break;
}
// b. 交换left和right指向的元素
nums[left] = nums[right];
nums[right] = val;
// c. 准备进行下一轮迭代
left++;
right--;
}
// 返回值:结果元素的个数
return left;
}
经检查发现在这两种特殊情况下,算法的处理逻辑正确,不用修改。
解法三:双指针——快慢指针插入元素
public int removeElement(int[] nums, int val) {
// 初始化slow和fast指针
int slow = 0, fast = 0;
while(true){
// a. 判断fast指针是否越界
if(fast >= nums.length){
break;
}
// b. 移动fast指针去寻找下一个结果元素(不等于val的元素)
while(nums[fast] == val){
fast++;
if(fast >= nums.length){
break;
}
}
// c. 再次判断fast是否越界
if(fast >= nums.length){
break;
}
// d. 将fast指向的元素插入slow所指位置
nums[slow] = nums[fast];
slow++;
// e. 准备开始寻找下一个结果元素
fast++;
}
return slow;
}
26. 删除有序数组中的重复项
解法:双指针——快慢指针插入元素
- slow:指向下一个插入元素的位置
- fast:用于遍历数组
在每一轮迭代中:
- 刚进入迭代体时,
fast
指向的元素即为当前元素,记为curNum
- 将当前元素插入
slow
指针指向的位置 - 移动
fast
指针,走完所有当前元素,如果越过数组边界就停下来 - 移动完
fast
指针时,可能处于以下两种情况之一:curNum
不是最后一个结果元素,fast
指针刚好指向下一个结果元素 => 准备进入下一轮迭代curNum
就是最后一个结果元素了,fast
指向数组末尾的下一位置 => 迭代结束直接退出
public int removeDuplicates(int[] nums) {
if(nums.length == 0) return 0;
int slow = 0, fast = 0;
int curNum;
while(true){
curNum = nums[fast];
// 将当前元素插入slow指针所指位置
nums[slow] = curNum;
slow++;
// 移动fast指针,走完所有当前元素
while(nums[fast] == curNum){
fast++;
if(fast >= nums.length){
break;
}
}
if(fast >= nums.length){
break;
}
}
return slow;
}
283. 移动零
本题要求既要保证结果元素的相对顺序,又要完成分区。因此可以先用“双指针——快慢指针插入元素”方法,在保证相对顺序的前提下,将所有的结果元素(非0元素)移到数组左侧,然后再继续移动slow
指针,将数组剩下的元素全部置0。
public void moveZeroes(int[] nums) {
int slow = 0, fast = 0;
while(true){
if(fast >= nums.length){
break;
}
// 移动fast指针,找到下一个非0元素
while(nums[fast] == 0){
fast++;
if(fast >= nums.length){
break;
}
}
if(fast >= nums.length){
break;
}
// 将fast指向的元素插入slow所指的位置
nums[slow] = nums[fast];
slow++;
fast++;
}
// 移动slow指针,将剩余元素全部置0
while(slow < nums.length){
nums[slow] = 0;
slow++;
}
}
844. 比较含退格的字符串
总体思路:
- 先分别对字符串
s
和字符串t
进行处理,删除字符串中的无效字符和退格符; - 然后再比较字符串
s
和字符串t
的内容
public boolean backspaceCompare(String s, String t) {
// 为了避免java中String对象的不变性对内存空间造成过大的影响,先将String转换为char[]
char[] sArray = s.toCharArray();
char[] tArray = t.toCharArray();
// Step1:删除字符串s和t中的无效字符和退格符
int sLen = helper(sArray);
int tLen = helper(tArray);
// Step2:比较字符串`s`和字符串`t`的内容
if(sLen != tLen) return false;
for(int i=0; i<sLen; i++){
if(sArray[i] != tArray[i]) return false;
}
return true;
}
其中int helper(char[] array)
函数的作用为:删除字符串array
中的无效字符和退格符,并返回删除后剩余有效元素的个数。
helper()
函数的实现思路:双指针——快慢指针插入元素
slow
指针:指向下一个插入元素的位置fast
指针:用于遍历数组,遇到非#元素就插入slow指向的位置,遇到#就将slow前移一位
private int helper(char[] array){
// slow指针:指向下一个插入元素的位置
// fast指针:用于遍历数组,遇到非#元素就插入slow指向的位置,遇到#就将slow前移一位
int slow = 0, fast = 0;
while(true){
if(fast >= array.length) break;
// 移动fast指针,直到找到一个非#元素
while(array[fast] == '#'){
fast++;
if(slow > 0) slow--; // 如果slow已经指向0位置了就不用向前退位了
if(fast >= array.length) break;
}
if(fast >= array.length) break;
// 将fast指向的元素插入slow指向的位置
array[slow] = array[fast];
slow++;
fast++;
}
return slow;
}
977. 有序数组的平方
public int[] sortedSquares(int[] nums) {
int[] numsSqrt = new int[nums.length];
// 借助双指针按照从大到小的顺序依次找到numsSqrt中的元素
int nextInsertPos = numsSqrt.length-1;
// 剩余元素中的平方最大元素一定是left和right指针指向的元素中的某一个
int left = 0, right = nums.length-1;
while(nextInsertPos >= 0){
if(nums[left]*nums[left] > nums[right]*nums[right]){
numsSqrt[nextInsertPos] = nums[left]*nums[left];
left++;
}else{
numsSqrt[nextInsertPos] = nums[right]*nums[right];
right--;
}
nextInsertPos--;
}
return numsSqrt;
}