数组移除元素leetcode练习

3 移除元素

3.1 例题1 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。题目链接

**方法1思路:**暴力解法,通过两个for循环来实现,第一个for循环进行数组的便利,找到和val相同的元素时进入第二个for循环,在第二个for循环中实现后方元素对前方元素的覆盖,离开第二个for循环后,将数组长度len–,再将i的值–,因为原位置已经被后面的数据覆盖。

代码如下:

class Solution {
    public int removeElement(int[] nums, int val) {
        int len = nums.length;

        for (int i = 0; i < len; i++){
            if (nums[i] == val) {
                for (int j = i; j < len-1; j++){
                    nums[j] = nums[j+1];
                }
                len--;
                i--;
            }
        }
        return len;
    }
}

**方法2思路:**只需一个for循环,该for循环用于遍历数组,在数组中新增一个判断条件,如果val不等于该位置的数值,则nums[k] = nums[i],且k++表示向后移动一个位置;如果val等于该位置的数值,则不进行操作。通过这种方式实现对val数值的替换。

代码如下:

class Solution {
    public int removeElement(int[] nums, int val) {
        int cnt = 0;
        for (int i = 0; i < nums.length; i++){
            if (nums[i] != val) {
                nums[cnt++] = nums[i];
            }
        }
        return cnt;
    }
}

方法一和方法二在内存消耗上相近,在时间复杂度上,法二更好。

**方法3思路:**双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。双指针法在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。(此处参考代码随想录)

代码如下:

class Solution {
    public int removeElement(int[] nums, int val) {
        int fastIndex = 0, slowIndex = 0;

        for (fastIndex = 0; fastIndex < nums.length; fastIndex++){
            if (nums[fastIndex] != val) { //如果快指针位置的数值和val相等,则将该位置的值赋值给慢指针所在的位置
                nums[slowIndex++] = nums[fastIndex];
            }
            //如果不相等,则不进行任何操作,相当于随着for循环的进行,快指针向后移动而慢指针位置不变
            //慢指针所在的位置始终是待替换数值的位置
        }
        return slowIndex;
    }
}

3.2 例题2 删除排序数组的中的重复项

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。题目链接

思路:采用双指针法。注意本题所给的数组是有序数组。和例题1相同,慢指针下一个位置的值都是待替换的,当快指针向后移动时,分为两种情况:

  • 如果本次循环快指针的值和慢指针的值相同,则不进行任何操作,进入下一次循环;
  • 如果本次循环快指针和慢指针的值不相同,则慢指针向后移动一位,并将快指针的值赋值给慢指针指向的位置。

代码如下:

class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums==null || nums.length == 1){
            return nums.length;
        }
        int slowIndex = 0, flatIndex = 1;
        for (; flatIndex < nums.length; flatIndex++){
            if (nums[slowIndex] != nums[flatIndex]) {
                slowIndex++;
                nums[slowIndex] = nums[flatIndex];
            }
        }
        return slowIndex+1;
    }
}

3.3 例题3 移动零

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

思路:如果数组为空或者数组长度为1,则不需要调整,直接返回结果即可;如果数组长度大于1,此时遍历数组,将index位置上的数据全部替换为nums数组上不为0的数值;最后,从index位置对数组进行for循环,将index后面的数据全部替换为0.

代码如下:

class Solution {
    public void moveZeroes(int[] nums) {
        if (nums.length <= 1 || nums == null){
            return;
        } 
        int index = 0;
        for (int i = 0; i < nums.length; i++){
            if (nums[i] != 0){
                nums[index++] = nums[i];
            }
        }
        for (int i = index; i < nums.length; i++){
            nums[i] = 0;
        }
        return;
    }
}

3.4 例题4 比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,请你判断二者是否相等。# 代表退格字符。

如果相等,返回 true ;否则,返回 false 。

注意:如果对空文本输入退格字符,文本继续为空。题目链接

**方法1思路:**采用栈的思想,创建两个String类型的数组。分别遍历数组s和t,如果该位置字符不为#,则将该字符连接到ss或tt后;如果为#,则将最后一个字符删除。最后对字符进行比较,如果相等返回true,不相等返回false.

代码如下:

class Solution {
    public boolean backspaceCompare(String s, String t) {
        String ss = "", tt = "";
        for (int i = 0; i < s.length(); i++){
            if (s.charAt(i) != '#') {
                ss = ss + String.valueOf(s.charAt(i));
            }
            else if (ss.length() != 0){
                ss = ss.substring(0, ss.length()-1);
            }
        }
        for (int i = 0; i < t.length(); i++){
            if (t.charAt(i) != '#') tt = tt + String.valueOf(t.charAt(i));
            else if (tt.length() != 0){
                tt = tt.substring(0, tt.length()-1);
            }
        }
        if (ss.compareTo(tt) == 0) return true;
        return false;
    }
}  

方法1有缺陷,执行时间和内存消耗比较大。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydsDj3BT-1642948952190)(C:\Users\lmh\AppData\Roaming\Typora\typora-user-images\image-20220123132343305.png)]

方法2思路:采用StringBuilder模拟栈,思路和方法1相似(参考代码随想录解析)

class Solution {
    public boolean backspaceCompare(String s, String t) {
        StringBuilder ssb = new StringBuilder(); // 模拟栈
        StringBuilder tsb = new StringBuilder(); // 模拟栈
        // 分别处理两个 String
        for (char c : s.toCharArray()) {
            if (c != '#') {
                ssb.append(c); // 模拟入栈
            } else if (ssb.length() > 0){ // 栈非空才能弹栈
                ssb.deleteCharAt(ssb.length() - 1); // 模拟弹栈
            }
        }
        for (char c : t.toCharArray()) {
            if (c != '#') {
                tsb.append(c); // 模拟入栈
            } else if (tsb.length() > 0){ // 栈非空才能弹栈
                tsb.deleteCharAt(tsb.length() - 1); // 模拟弹栈
            }
        }
        return ssb.toString().equals(tsb.toString());
    }
}  

3.5 例题5 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。题目链接

思路:双指针法(前后指针),left表示左指针,right表示右指针,将两个指针所指位置数值的平方进行比较并加入到新创建的数组res中。

代码如下:

class Solution {
    public int[] sortedSquares(int[] nums) {
        if (nums.length == 0) return nums;
        int left = 0, right = nums.length-1;
        int len = nums.length - 1;
        int []res = new int[len+1];

        while (left <= right) {
            if (nums[left]*nums[left] < nums[right]*nums[right]) {
                res[len--] = nums[right] * nums[right];
                right--;              
            }else if (nums[left]*nums[left] > nums[right]*nums[right]){
                res[len--] = nums[left] * nums[left];
                left++;
            }else {
                res[len--] = nums[left] * nums[left];
                left++;
            }
        }
        return res;
    }
}

你可能感兴趣的:(排序算法,leetcode,算法)