跳转至

Leetcode Hot100 双指针

283. 移动零 - 力扣(LeetCode)

class Solution {
    public void moveZeroes(int[] nums) {
        int writePointer = 0; 
        for (int num:nums) { // 遍历数组中的每个元素
            if (num != 0) {
                nums[writePointer] = num; // 非0元素,直接写入数组更改
                writePointer++;
            }
        }
        for (int i = writePointer; i<nums.length; i++) {nums[i] = 0;} // 剩余位置全部填充0
       }
}

**复杂度分析**
- **时间复杂度O(n)**其中 n 是数组的长度遍历数组两次第一次遍历非零元素第二次填充零总时间复杂度是 O(n)
- **空间复杂度O(1)**只使用了常数级别的额外空间

双指针解法

class Solution {
    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++;
        }
    }

    // 交换数组中两个位置的元素
    public void swap(int[] nums, int left, int right) {
        // 当 right 指针遇到非零元素时,将其与 left 指针位置的元素交换,并将 left 指针右移
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

**复杂度分析**
- **时间复杂度O(n)**其中 n 是数组的长度整个过程中left  right 指针最多各移动 n 因此总操作次数为 O(n)
- **空间复杂度O(1)**只使用了常数级别的额外空间没有使用额外的数据结构

11. 盛最多水的容器 - 力扣(LeetCode)

class Solution {
    public int maxArea(int[] height) {
        // 就是在 x距离最远的前提下,尽量选择最长的线
        // 以两边中的最短边和 i2 - i1 为底
        // 使用双指针移动,记录当前的最大容量,因为间隔是一致的1
        // 然后就保持长边不变,最短边移动,更新最大容量即可

        int left = 0; // 左指针从最左端开始
        int right = height.length - 1; // 右指针从最右端开始
        int maxArea = 0; // 记录最大容量

        while (left < right) {
            // 计算当前容量:较短边的高度 * 两指针之间的距离
            int currentArea = Math.min(height[left], height[right]) * (right - left);
            // 更新最大容量
            maxArea = Math.max(maxArea, currentArea);

            // 移动较短的边,寻找更大的容量
            // 因为对于当前的容量,较短的边是限制容量的,所以移动较短的边可以尝试找到更大的容量
            if (height[left] < height[right]) {
                left++; // 左边较短,左指针右移
            } else {
                right--; // 右边较短,右指针左移
            }
        }

        return maxArea;
    }
}

---
双指针算法通过每次移动较短的边确保了每一步都在寻找可能的更大容量同时避免了不必要的计算虽然看起来可能会错过某些组合但实际上这些组合的容量一定小于或等于已经计算过的容量
---
**复杂度分析**
- **时间复杂度O(n)**其中 n 是数组的长度双指针从两端向中间移动最多遍历数组一次
- **空间复杂度O(1)**只使用了常数级别的额外空间

15. 三数之和 - 力扣(LeetCode)

看了官方的伪代码后,基于自身理解修改正例得到的代码。 理解固定和指针左行

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        /*
        首先排序,降低重复数字造成的影响
            只有当值不同的时候才会进行枚举
        遍历数组,每次固定一个数
        跳指针,双指针,右指针左行
        */
        int n = nums.length; // 定义数组长度,后续要多次使用
        Arrays.sort(nums); // 排序
        List<List<Integer>> li = new ArrayList<List<Integer>>(); // 建立存储集合
        // 定义第一个数
        for (int i = 0; i < n; ++i) {
            // 需要和上一次枚举的数不相同
            if (i > 0 && nums[i] == nums[i - 1]) {
                // 即:第一个数的下标不是0,且第一个数和第二个数相同的时候跳过判断
                // 因为这个情况在下标为0的时候已经枚举过了
                continue;
            }
            // 定义第三个数所对应的指针
            int right = n - 1; //初始指向数组的最右端

            // 定义第二个数
            for (int j = i + 1; j < n; ++j) {
                // 首先,定义第二个数的下标是在第一个数之后的
                // 如果第二个数和第一个数出现相同,说明这个情况在之前的枚举轮次已经枚举过了
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                // 需要保证 第二个数 的指针在 第三个数的 的指针的左侧
                // 即始终保持 a b c, a+b+c 的组合顺序
                while (j < right && nums[i] + nums[j] + nums[right] > 0) {
                    --right;
                }
                // 如果指针重合,随着 b 后续的增加,将不再有满足 a+b+c=0 ,a->b->c这个顺序的组合了,可以退出循环
                if (j == right) {
                    break;
                }
                if (nums[i] + nums[j] + nums[right] == 0) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[right]);
                    li.add(list);
                }
            }
        }
        return li;
    }
}

评论