秋招力扣Hot100刷题总结——双指针

1. 三数之和 题目链接

  • 题目要求:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
    注意:答案中不可以包含重复的三元组。
    在这里插入图片描述
  • 代码及思路
    • 使用双指针解决问题
    • 首先对数组进行排序,然后遍历数组,对每一个元素使用双指针从该元素下一个位置和数组最后一个元素进行遍历求和
    • 注意两次去重:一次是元素遍历时与前一个元素相同时去重,一次是双指针遍历时去重
    • 剪枝:排序后若数组第一个元素就大于0,那就直接返回;遍历数组时只需要遍历到倒数第三个元素
    • 代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res=new ArrayList<>();
        Arrays.sort(nums);
        if(nums[0]>0)return res;
        for(int i=0;i<nums.length-2;i++){
            if(i>0&&nums[i]==nums[i-1])continue;
            int left=i+1;
            int right=nums.length-1;
            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
                    List<Integer> temp=new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    res.add(temp);
                    int leftval=nums[left];
                    while(left<right && nums[left]==leftval){
                        left++;
                    }
                }else if(sum>0){
                    right--;
                }else {
                    left++;
                }
            }
        }
        return res;
    }
}

2. 搜索旋转排序数组 题目链接

  • 题目要求:整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
在这里插入图片描述

  • 代码及思路
    • 使用二分查找来解决,且虽然数组进行了旋转,但至少有一半是有序的
    • 通过比较 nums[left] 和 nums[mid] 或 nums[mid] 和 nums[right],确定左半部分或右半部分是否有序
    • 根据目标值 target 是否在有序部分的范围内,调整 left 和 right 的位置
    • 代码
class Solution {
    public int search(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                return mid;
            }else if(nums[left]<=nums[mid]){
                if(target>=nums[left]&&nums[mid]>target){
                    right=mid-1;
                }else{
                    left=mid+1;
                }
                
            }else if(nums[mid]<nums[right]){
                if(nums[mid]<target&&target<=nums[right]){
                    left=mid+1;
                }else{
                    right=mid-1;
                }
            }
        }
        return -1;
    }
}

3. 在排序数组中查找元素的第一个和最后一个位置 题目链接

  • 题目要求:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
    如果数组中不存在目标值 target,返回 [-1, -1]。
    你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
    在这里插入图片描述
  • 代码及思路
    • 首先使用双指针找到指定元素的第一个位置
    • 然后分别循环找到该元素的左右边界
    • 代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res={-1,-1};
        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                int maxL=mid;
                int maxR=mid;
                while(maxL>0&&nums[maxL-1]==target){
                    maxL--;
                }
                while(maxR<nums.length-1&&nums[maxR+1]==target){
                    maxR++;
                }
                res[0]=maxL;
                res[1]=maxR;
                return res;
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return res;
    }
}

4. 盛最多水的容器 题目链接

  • 题目要求:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
    找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
    返回容器可以储存的最大水量。
    说明:你不能倾斜容器。
    在这里插入图片描述
  • 代码及思路
    • 使用双指针,左指针从数组最开始向后遍历,右指针从数组尾向前遍历
    • 每次遍历以左右指针的差为宽度,以二者中较小的高为高更新容量
    • 选择左右指针中较小的一个进行移动
    • 代码
class Solution {
    public int maxArea(int[] height) {
        int left=0;
        int right=height.length-1;
        int res=0;
        while(left<right){
            int width=right-left;
            int high=Math.min(height[left],height[right]);
            res=Math.max(res,width*high);
            if(height[left]<height[right]){
                left++;
            }else{
                right--;
            }
        }
        return res;
    }
}

5. 颜色分类 题目链接

  • 题目要求:给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
    我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
    必须在不使用库内置的 sort 函数的情况下解决这个问题。
    在这里插入图片描述
  • 代码及思路
    • 使用三个指针,左指针表示0应该放的位置,右指针表示2应该放的位置,cur指针遍历数组
    • 当前元素为2时,cur指针所在元素和右指针交换,但不向后移动
    • 当前元素为1时,cur指针向后移动
    • 当前元素为0时,cur指针和左指针交换,并且向后移动一位
    • 代码
class Solution {
    public void sortColors(int[] nums) {
        int left=0;
        int right=nums.length-1;
        int cur=0;
        while(cur<=right){
            if(nums[cur]==0){
                int temp=nums[left];
                nums[left]=nums[cur];
                nums[cur]=temp;
                cur++;
                left++;
            }else if(nums[cur]==1){
                cur++;
            }else{
                int temp=nums[right];
                nums[right]=nums[cur];
                nums[cur]=temp;
                right--;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值