算法通关村第三关-白银挑战:双指针解决删除重复元素、删除指定元素、数组元素奇偶移动问题

双指针

  • 我们使用双指针,能够很清晰、方便地解决问题,接下来我们使用双指针来解决一些典型问题:

删除重复元素

  • 给定一个数组,要求删除其中所有重复元素,重复元素保留一个
  • 对于这种问题,我们使用快慢双指针来解决:

    • 快指针在前,慢指针在后,快指针向前移动

    • 如果快指针所指元素,与此时慢指针所指元素相同即重复元素),则慢指针等待,快指针继续向前移动

    • 如果快指针所指元素,与此时慢指针所指元素不相同,则慢指针:先记录快指针指向的值,然后向前移动,快指针继续向前移动

    • 循环执行,直到快指针移动到右边界为止

    • 即:慢指针左侧维护了所有未重复的元素值
  • 具体代码实现如下:(2023/08/13午)
 /**
     * 快慢指针
     *
     * @param nums
     * @return
     */
    public static int removeDuplicates(int[] nums) {
        // slow维护左侧,未重复元素
        int slow = 1;
        // 快指针移动
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != nums[slow - 1]) {
                // slow负责维护未重复的元素
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }

删除指定元素

  • 给定一个数组,要求删除指定元素
  • 对于这种问题,我们也可以使用双指针解决,且有两种思路:

    • 快慢双指针

    • 对撞双指针

  • 快慢双指针的思路与上面如出一辙,无非是:快指针寻找的元素不再是与慢指针重复的元素,而是指定元素

  • 具体代码如下:(2023/08/13午)
/**
     * 快慢双指针
     *
     * @param nums
     * @param val
     * @return
     */
    public static int removeElement(int[] nums, int val) {
        int slow = 0;
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //最后剩余元素的数量
        return slow;
    }
  • 这里简单捋一捋对撞双指针的思路:(2023/08/13午)
    • 左指针在左,右指针在右,左指针向前移动

    • 如果左指针未找到指定元素,则左指针继续向前移动

    • 如果左指针找到了指定元素,就拿右指针所指元素覆盖,左指针向前移动,右指针向后移动

    • 循环执行,直到两指针碰撞

    • 即:左指针左侧维护了所有正确的元素值

  • 使用对撞双指针解决思路:(2023/08/15晚)
    • 设左右双指针

    • 左指针向前移动,遇到指定元素就停下来

    • 这时,将两指针所指元素交换,右指针向前一步

    • 重复以上操作,直至两指针相撞

  • 具体代码实现如下:(2023/08/13午)
 /**
     * 对撞双指针
     *
     * @param nums
     * @param val
     * @return
     */
    public static int removeElement3(int[] nums, int val) {
        // 1.定义左右指针
        int right = nums.length - 1;
        for (int left = 0; left < right; ) {
            // 2.左指针找到目标元素
            if (nums[left] == val) {
                // 3.右指针覆盖左指针
                nums[left] = nums[right];
                right--;
            } 
            
            left++;    
        }
        return right;
    }

元素奇偶移动专题

  • 情景:

  • 给你一个数组,设计一种算法,要求操作结束后,数组中所有偶数都在左,所有奇数都在右
  • 首先想到的方法应该是:new一个新数组,把该数组遍历两遍,依次将偶数元素、奇数元素先后插入 ✔

  • 那么有没有不开辟新空间,即空间复杂度为O(1)的算法呢?
  • 当然有:

    • 设左右双指针

    • 左指针遇到偶数元素就跳过,遇到奇数元素就停下来

    • 右指针相反遇到奇数元素就跳过,遇到偶数元素就停下来

    • 这时,将两指针指向元素交换

    • 重复以上操作,直至两指针相撞

  • 这不就是 “对撞双指针” 思想吗?,具体代码如下:(2023/08/15晚)
 /**
     * 双指针,不稳定 的移动
     *
     * @param A
     * @return
     */
    public static int[] sortArrayByParity(int[] A) {
        int left = 0, right = A.length - 1;
        while (left < right) {
            if (A[left] % 2 > A[right] % 2) {
                int tmp = A[left];
                A[left] = A[right];
                A[right] = tmp;
            }
​
            if (A[left] % 2 == 0) left++;
            if (A[right] % 2 == 1) right--;
        }
​
        return A;
    }

你可能感兴趣的:(算法通关村,算法,c++,java)