【代码随想录】【数组】移除元素 双指针 快慢指针插入元素 左右指针分区

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;
}

解法二:双指针——左右指针分区

image.png

根据初步思路写出代码:

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--;
    }
}

image.png

在之前的代码中加入迭代终止条件,以及函数返回值:

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;
}

image.png

经检查发现在这两种特殊情况下,算法的处理逻辑正确,不用修改。

解法三:双指针——快慢指针插入元素

image.jpeg

image.jpeg

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. 移动零

image.png

本题要求既要保证结果元素的相对顺序,又要完成分区。因此可以先用“双指针——快慢指针插入元素”方法,在保证相对顺序的前提下,将所有的结果元素(非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. 比较含退格的字符串

总体思路:

  1. 先分别对字符串s和字符串t进行处理,删除字符串中的无效字符和退格符;
  2. 然后再比较字符串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;
}
  • 27
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值