【思路详解+详细注释】小白都能看懂的力扣算法详解——双指针

一 LC283.移动零

题目要求:

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

283. 移动零 - 力扣(LeetCode)

思路分析:

       本题是很经典的一道快慢指针题目。我们可以定义两个指针,起始都指向数组的首个元素。其中,我们让快指针循环遍历整个数组,当快指针移动到数组末尾时,退出循环。

        在遍历过程中,我们始终让快指针向前移动1,如果此时快指针指向的元素为0,则继续向前移动,如果不为0,则与慢指针指向的元素进行交换,然后两个指针同时向前移动。当快指针遍历完毕整个数组,则交换全部完成。

完整代码示例:

class Solution {
    public void moveZeroes(int[] nums) {
        int f = 0; // 左指针指向首个元素
        int s = 0; // 慢指针
        while(f != nums.length) {
           if(nums[f] == 0) {
            f++;
           }else {
            int temp  = nums[f];
            nums[f] = nums[s];
            nums[s] = temp;
            s++;
            f++;
           }
        }

    }
}

二 LC11.盛最多水的容器

题目要求:

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

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

思路分析:

       这道题目同样难度没有那么高,分析题目,不难看出,我们需要找到数组中两个元素间数值较小的那个元素 * 数组元素下标差最大的那个结果。

        我们同样使用双指针的方法完成,这次我们定义两个指针,分别指向数组的头尾(此时元素下标差最大),我们计算这时两个元素中较小数 * 下标差的值,并进行记录。这时,如果我们希望扩大乘积的值,那么只能考虑增加最小元素的数值,因此,我们将指向较小数值元素的指针向中间移动,保留指向较大元素的指针不变。继续计算乘积,并将新计算出的结果与之前的结果对比,留下较大的那一个。直到两个指针相遇,距离变为0时结束循环。

完整代码示例:

class Solution {
    public int maxArea(int[] height) {
        int res = 0;
        int l = 0;
        int r = height.length - 1;
        while( l <= r ) {
            int area = Math.min(height[l], height[r]) * (r - l);
            if(area > res) res = area;
            if (height[l] <= height[r]) {
                l = l + 1;
            }
            else {
                --r;
            }
        }
        return res;
    }
}

三 LC15.三数之和

题目要求:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

思路分析:

       本题要求找到满足条件的所有三元组,并去除重复的可能。因此我们考虑使用双指针来进行。首先我们对数组进行排序,遍历排序后的数组。定义两个指针,分别指向当前遍历元素的下一个元素和数组末尾元素,当左指针小于右指针时,进行循环。此外还需要判断如果当前元素已经大于0了,那么其后面的元素一定大于0,不满足题目要求,可以直接return。当遍历到重复元素时也直接跳过,避免出现重复的解。

        当当前元素与左右指针指向的元素之和等于0时,记录该结果,并移动指针(注意跳过重复元素);如果当前元素与左右指针指向的元素之和大于0,则将右指针向左移动,否则向右移动左指针。

完整代码示例:

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        Arrays.sort(nums);
        int len = nums.length;
        for(int i = 0;i < len;++i) {
            if(nums[i] > 0) return lists; // nums[i]已经大于0了,直接return
            if(i > 0 && nums[i] == nums[i-1]) continue; //遍历到重复元素时直接跳过,避免出现重复解。
            int curr = nums[i];
            int L = i+1, R = len-1;
            while (L < R) {
                int tmp = curr + nums[L] + nums[R];
                if(tmp == 0) {
                    List<Integer> list = new ArrayList<>(); // 记录结果
                    list.add(curr);
                    list.add(nums[L]);
                    list.add(nums[R]);
                    lists.add(list);
                    while(L < R && nums[L+1] == nums[L]) ++L; // 跳过重复元素
                    while (L < R && nums[R-1] == nums[R]) --R; // 跳过重复元素
                    ++L;
                    --R;
                } else if(tmp < 0) {
                    ++L;
                } else {
                    --R;
                }
            }
        }
        return lists;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值