双指针总结

本文总结了双指针算法在多种常见问题中的应用,如k-diff数对、长按键入、合并区间等,涵盖了排序、查找、去重、滑动窗口等核心技巧。通过实例分析和代码演示,助你理解和掌握双指针算法在信息技术中的高效实践。
摘要由CSDN通过智能技术生成


常见双指针算法分为三类,同向(即两个指针都相同一个方向移动),背向(两个指针从相同或者相邻的位置出发,背向移动直到其中一根指针到达边界为止),相向(两个指针从两边出发一起向中间移动直到两个指针相遇)

532. 数组中的 k-diff 数对(前后指针)

class Solution {
    public int findPairs(int[] nums, int k) {
        /**
        分析:
        题意中是要返回不同数对的数量,那么(1,2)和(2,1)其实本质是一样的,这里规定从小到大排序,即数对是非严格递增的==》将数组排好序,利用双指针特性,在合适的时候,进行前后指针的移动
        
         */
         Arrays.sort(nums);
         int len = nums.length;
         if(len < 2){
             // 只有一个数,不会构成数对
             return 0;
         }
         // 结果
         int res = 0;
         // 至少是两个数
         int left = 0;
         int right = 1;
         while(left <= right && right < len){
             if(nums[right] - nums[left] == k){
                 // 找到数对
                 res++;
                 // 下面的逻辑是解题的关键!!!
                 // 移动右指针并判断指针数与前一个数是否重合
                do{
                    right++;
                }while(right < len && nums[right] == nums[right-1]);
                // 移动左指针并判断指针值与前一个数是否重合
                do{
                    left++;
                }while(left < right &&nums[left] == nums[left - 1]);
             }else if(nums[right] - nums[left] > k){
                 // 移动左指针
                 left++;
             }else{
                 // 移动右指针
                 right++;
             }
             // 两个指针必须对应数组中的两个数
             if(left == right){
                 // 两指针重合,右指针走一步
                 right++;
             }
             
         }
         return res;
    }
}

注意:这种题目还可以用哈希表,在使用哈希表过程中要时刻保持对HashMap和HashSet的敏感度,其中HashMap的使用,有些储存的是值-下标,有些储存的是值-个数,有些储存的是值-值。根据题目,灵活使用!

class Solution {
    public int findPairs(int[] nums, int k) {
        /*
        这道题其实很像two-sum的变种题,一看到两数相加等于一个target,第一个想法就是哈希表,唯一不同的点就在于,这里数对的定义(1,2)和(2,1)是同一个数对,所以核心思路就是如何去去重==》数组预先排序,定义一个储存数对的哈希表和储存遍历元素的哈希表
        注意:这里是对HashSet的使用,扩充了去除重复元素的思路。
        */
        Arrays.sort(nums);
        // 储存数对的哈希表
        Map<Integer,Integer> map = new HashMap<>();
        // 储存遍历元素的哈希表
        Set<Integer> set = new HashSet<>();
        // 遍历元素
        for(int i = 0; i < nums.length; i++){
            if(set.contains(nums[i] - k)){
                // set中有遍历元素,那么储存数对
                map.put(nums[i],nums[i] - k);
            }
            // 储存遍历元素,比如有n个1,最后set中只会有一个1,达到去重目的
            set.add(nums[i]);
        }
        // map的大小就是数对中的个数
        return map.size();
    }
}

925. 长按键入

class Solution {
    public boolean isLongPressedName(String name, String typed) {
        /**
        分析:
        题目的意思就是name中的一个字母可能对应typed中多个相同字母,那么这里就可以使用个一个计数变量count,当count>0时,说name中的字母出现的次数比typed中字母出现的次数还要高,就直接返回false。
        当遍历完name后,若发现还没有遍历完typed,则发现typed中存在多余的字符,这时候,也是返回false,反之返回true
        
         */
         // 特判
         if(name.length() == 0 || typed.length() == 0){
             return false;
         }
         int i = 0;
         int j = 0;
         while( i < name.length()){
             // 定义一个计数变量count
             int count = 0;
             // 定义字符ch
             char ch = name.charAt(i);
             // 遍历name中所有ch字符
             while( i < name.length() && name.charAt(i) == ch){
                 // 找到ch字符,+1
                 count++;
                 // 移动指针
                 i++;
             }
             // 遍历typed中所有ch字符
             while( j < typed.length() && typed.charAt(j) == ch){
                 // 找到ch字符,-1
                 count--;
                 // 移动指针
                 j++;
             }
             // 在本轮侦查过程中,发现count>0,则返回false
             if(count > 0){
                 return false;
             }
         }
         // 遍历完name后,发现j不等于typed的长度,则返回false
         return j == typed.length();

    }
}

56. 合并区间

class Solution {
    public int[][] merge(int[][] intervals) {
        /**
        分析:
        第一想法就是对二维数组排好序,定义结果数组,对原始数组单层循环遍历,根据条件判断是否应该合并。
        第一次解法的误区就是没有定义好双指针,当发生合并时,指针没有及时更新。
        还有就是对最后一组数组要进行添加。
         */
         if(intervals.length == 1){
             return intervals;
         }
         // 定义结果数组和区间个数count
         int[][] res = new int[intervals.length][2];
         int count = 0;
         // 对二维数组进行排序
         Arrays.sort(intervals,(a,b) -> {return a[0] - b[0];});
         // 定义初始双指针
         int start = intervals[0][0],end = intervals[0][1];
         // 遍历数组,从第二组开始
         for(int i = 1; i < intervals.length; i++){
             // 后一组区间的下界比end小
             if(intervals[i][0] <= end){
                 // 更新指针的end界限
                 end = Math.max(end,intervals[i][1]);
             }else{
                 // 合并区间
                 res[count][0] = start;
                 res[count][1] = end;
                 count++;
                 // 双指针指向新区间
                 start = intervals[i][0];
                 end = intervals[i][1];

             }
         }
         // 添加最后一组数据
         res[count][0] = start;
         res[count][1] = end;
         count++;
         // 截取二维数组
         return Arrays.copyOfRange(res,0,count);

    }
}

75. 颜色分类

class Solution {
    public void sortColors(int[] nums) {
        //计数排序,时间复杂度为O(m+n)
		int[] color = new int[3];
		for(int num:nums) {
			color[num]++;		//将颜色叠加,储存个数
		}
		int k=0;
		for(int j=0;j<3;j++) {
			while(color[j]--!=0) {
                // 依次输出个数
				nums[k++]=j;
			}
		}
    }

}

80. 删除有序数组中的重复项 II&26. 删除有序数组中的重复项(快慢指针&套路魔板题型)

class Solution {
    public int removeDuplicates(int[] nums) {
        /**
        分析;
        这一题和26题是一模一样,只不过这里元素最多出现2次。
        使用方法依旧是快慢指针原地修改数组.
        慢指针用来原地修改数组,只有满足特定条件,慢指针才会走
        快指针用来遍历
         */
         int len = nums.length;
         if(len <= 2){
             return len;
         }
         // 定义快慢指针
         int slow = 2;
         int fast = 2;
         while(fast < len){
             // 当nums[slow-2] != nums[fast],意味着fast是符合题意的
             if(nums[slow - 2] != nums[fast]){
                 // 原地修改数组
                 nums[slow] = nums[fast];
                 // 移动慢指针
                 slow++;
             }
             // 快指针移动
             fast++;
         }
         // 最后返回慢指针,就是个数了
         return slow;

    }
}

注意:这里的核心在于考虑清楚nums[slow-2] = nums[fast]时,那么num[slow-2]=nums[slow-1]=nums[fast]必然存在!

class Solution {
    public int removeDuplicates(int[] nums) {   
        return process(nums, 2);
    }
    int process(int[] nums, int k) {
        int u = 0; 
        for (int x : nums) {
            if (u < k || nums[u - k] != x) nums[u++] = x;
        }
        return u;
    }
}

注意:这里的核心在于保留k个数,同时判别前k个数是否与当前数相等,其实本质和快慢指针是一样一样的,只不过这里将其泛化了,更有通用性

485. 最大连续 1 的个数(可变滑动窗口魔板)

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        /**
        分析:
        这是一个求解最大连续数组问题,因此立刻就想到滑动窗口。
        每次记录更新窗口的最大值。
        可变滑动窗口解题魔板:
                l 和 r 都初始化为 0
                r 指针移动一步
                判断窗口内的连续元素是否满足题目限定的条件
                如果满足,再判断是否需要更新最优解,如果需要则更新最优解。并尝试通过移动 l 指针缩小窗口大小。循环执行,如果不满足,则继续。
                形象地来看的话,就是 r 指针不停向右移动,l 指针仅仅在窗口满足条件之后才会移动,起到窗口收缩的效果。
        
         */
         int len = nums.length;
         int left = 0;
         int right = 0;
         int count = 0;
         while(left <= right && right < len){
             // 遇到0,就要更新个数,这时候就要缩小窗口了
             if(nums[right] == 0){
                 // 更新个数
                 count = Math.max(count,right - left );
                 // 保证left和right又指向同一个数,继续探寻count
                 left = right + 1;
             }
             // 右指针移动
             right++;
         }
         // 处理数组最后一组1,取最大值
         count = Math.max(count,len - left );
         return count;

    }
}

注意:本题一定要掌握滑动窗口的判别,求解连续子数组问题!!!同时牢记滑动窗口魔板,定义left和right指针为0,right指针一直走,在特点条件下,缩小滑动窗口,更新left指针(这里要根据题目实际场景!),然后使用Math函数,实时更新窗口的最大最小值,最后别忘记处理末尾一组数据!

11. 盛最多水的容器

暴力法结果时间超时,所以要优化思路,采用双指针法!

class Solution {
    public int maxArea(int[] height) {
        /**
        分析:容纳最多的水等价于横坐标之间的距离乘以高
        暴力法:遍历,最后显示时间超时!算法需要优化
         */
        int n = height.length;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int area = Math.min(height[i], height[j]) * (j - i);
                ans = Math.max(ans, area);
            }
        }
        return ans;

    }
}

本题中核心就是理解面积的增大最有可能在于短板的提升,移动长板是不会增大面积的(因为面积在于短板高度,移动指针后,两指针指针的距离就又减少的),时间复杂度为O(n)

class Solution {
    public int maxArea(int[] height) {
        /**
        本题中核心就是理解面积的增大最有可能在于短板的提升,移动长板是不会增大面积的(因为面积在于短板高度,移动指针后,两指针指针的距离就又减少的)
        双指针:左右双指针法,在特定条件下移动指针
         */
         int left = 0;
         int right = height.length - 1;
         // 定义结果
         int res = 0;
         while(left < right){
             // 寻找短板,移动短板
             if(height[left] < height[right]){
                 res = Math.max(res,(right - left) * height[left] );
                 // left是短板
                 left++;
                 
             }else{
                 res = Math.max(res,(right - left) * height[right] );
                 // right是短板
                 right--;
             }
         }
         return res;

    }
}

26. 删除有序数组中的重复项

注意:原地修改数组,第一想法就要想到快慢指针!!!

class Solution {
    public int removeDuplicates(int[] nums) {
        /**
        分析:
        数组已经有序,并且是原地修改数组(原地修改数组首先就应该想到用快慢指针法)
        快指针一直移动,慢指针只有在特定情况下移动
         */
         int fast = 0;
         int slow = 0;
         while(fast < nums.length){
             if(nums[slow] != nums[fast]){
                 // 两者不相等的时候,慢指针移动了
                 nums[++slow] = nums[fast];
             }
             // 快指针一直移动
             fast++;
         }
         return slow+1;

    }
}

27. 移除元素

class Solution {
    public int removeElement(int[] nums, int val) {
        /**
        原地移除特定数值(其实就是原地修改数组)==》快慢指针法
         */
         // 特判
         if(nums.length == 0){
             return 0;
         }
         int fast = 0;
         int slow= 0;
         while(fast < nums.length){
             if(nums[fast] != val){
                 nums[slow++] = nums[fast];
             }
             // 快指针移动
             fast++;
         }
         return slow;

    }
}

125. 验证回文串

class Solution {
    public boolean isPalindrome(String s) {
        /**
        分析:
        判断回文串很明显使用双指针==》对撞指针法
        回文串的判别只考虑字母(忽略字母大小写)和数字字符==》遍历字符串存入数组中!
        本题更多考察的是api的使用:
        - 字符是否为字母:Character.isLetter()
        - 字符是否为数字:Character.isDigit()
        - 字符是否为字母或者数字:Character.isLetterOrDigit()
        - 字符转化为小写:Character.toLowerCase()
        - 字符转化为大写:Character.toUpperCase()
         */
         int len = s.length() - 1;
         int left = 0, right = len;
         while(left < right){
             // 忽略左边无效字符
             while( left < right && !Character.isLetterOrDigit(s.charAt(left))){
                 left++;
             }
             // 忽略右边无效字符
             while( left < right && !Character.isLetterOrDigit(s.charAt(right))){
                 right--;
             }
             // 统一成小写字母进行回文验证
             if(Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))){
             return false;    
             }
             left++;
             right--;
         }
         return true;
    }
}

238. 除自身以外数组的乘积

class Solution {
    public int[] productExceptSelf(int[] nums) {
        /**
        分析:
        一般思路是遍历数组,将所有数字乘积,然后除以索引上的数字(如果遇到索引上的数字为0,则失效),题目也规定了不能采用该方法。
        那么可以考虑乘积列表法,将该索引左边的乘积和右边的乘积再次相乘最后可以得到答案!
         */
        // 定义左右乘积数组
        int len = nums.length;
        int[] left = new int[len];
        int[] right = new int[len];
        // 遍历数组
        // left[0] 初始化为1
        left[0] = 1;
        for(int i = 1; i < len; i++){
            left[i] = left[i - 1] * nums[i - 1];
        }
        // right[len - 1] 初始化为1
        right[len - 1] = 1;
        for(int i = len -2; i >= 0; i--){
            right[i] = right[i + 1] * nums[i + 1];
        }
        int[] res = new int[len];
        // 最后左右乘积数组再次相乘
        for(int i = 0; i < len; i++){
            res[i] = left[i] * right[i];
        }
        return res;
    }
}

注意:本题带给我的收获是分治的思想,一次性算不出来,那么分两次(左边两边存储起来~)很多题目都用到了这种思想!!!

448. 找到所有数组中消失的数字(原地哈希)

注意:第一种方法是常规的使用哈希表法

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        /**
        分析:
        将1-n储存到哈希表中,遍历数组,如果存在则移除哈希表对应值,最后返回哈希表中余下的个数
         */
         Set<Integer> set = new HashSet<>();
         List<Integer> res = new ArrayList<>();
         int n = nums.length;
         // [1,n]添加到哈希表中
         for(int i = 1; i <= n; i++){
             set.add(i);
         }
         for(int i = 0; i < n; i++){
             if(set.contains(nums[i])){
                 // 移除哈希表
                 set.remove(nums[i]);
             }
         }
         // 添加剩下的元素
         for(Integer i: set){
             res.add(i);
         }
         return res;

    }
}

注意:第二种方法使用的是原地哈希法!很巧妙,关键是理解数组nums[i]为[1,n],而数组的下标是[0,n-1],先将数组“排好序”

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        /**
        分析:
        思考:
        数组nums[i]为[1,n],而数组的下标是[0,n-1],可以考虑原地哈希!
        按照正常逻辑来说,如果数组是排好序的,那么下标与数组值nums[i]的关系是下标i+1 = nums[i]。
        相等的话,index++,对下一个数进行位置寻找,如果不相等,就将数字放到正确的位置中(这里又有两种情况:1正确位置的值与当前位置的值相等,ok,index++,continue循环2正确为值的与当前位置的值不相等,ok,交换两个空间,并且保持index不变对当前index继续探索)
        最后遍历“排好序的数组”,若发现index+1不等于当前数组值,则就是缺失的元素(index+1)。
         */
         int len = nums.length;
         int index = 0;
         while(index < len){
             // 遍历数组,探寻数组正确位置
             if(nums[index] == index + 1){
                 // index+1 和当前值一致,“这个排好序了”,index++
                 index++;
             }else{
                 // 不一致,那么继续探索正确位置
                 int targetIndex = nums[index] - 1;
                 if(nums[targetIndex] == nums[index]){
                     // 若探索到的位置值和当前的值一样(重复元素),那么index++,跳过当前循环
                     index++;
                     continue;
                 }
                 // 和当前位置不一致,那么就可以进行交换,交换后继续探索当前index的正确位置
                 int temp = nums[targetIndex];
                 nums[targetIndex] = nums[index];
                 nums[index] = temp;
             }
         }
         List<Integer> res =  new ArrayList<>();
         // 遍历“排好序的数组”
         for(int i = 0; i < len; i++){
             // 发现“排序好数组中”下标+1不等于当前值,说明该数是重复的元素
             if( i + 1 != nums[i] ){
                 // 添加缺失的元素 i + 1
                 res.add(i + 1);
             }
         }
         return res;

    }
}

442. 数组中重复的数据(原地哈希,和448一致)

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        /**
        分析:
        数组中的元素只有两种情况:出现一次或者出现两次
        重复问题的==》哈希表
        题目规定不使用额外空间==》。。。
         */
         Set<Integer> set = new HashSet<>();
         List<Integer> res = new ArrayList<>();
         for(int i = 0; i < nums.length; i++){
             if(set.contains(nums[i])){
                 res.add(nums[i]);
             }
             // 添加到哈希表中
             set.add(nums[i]);
         }
         return res;
 
    }
}
class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        /**
        本题思路和448题思路一致,依旧使用原地哈希的思想(数组nums[i]值为[1,n],下标为[0,n-1])。
        那么就把数组“排好序”,正确的位置中num[i] == i + 1,错误位置就是出现两次的元素了!
         */
         int len = nums.length;
         int index = 0;
         while(index < len){
             if(nums[index] == index+1){
                 index++;
             }else{
                 int targetIndex = nums[index] - 1;
                 if(nums[targetIndex] == nums[index]){
                     index++;
                     continue;
                 }
                 int temp = nums[targetIndex];
                 nums[targetIndex] = nums[index];
                 nums[index] = temp;
             }
         }
         List<Integer> res = new ArrayList<>();
         for(int i = 0; i <len; i++){
             if(i+1 != nums[i]){
                 res.add(nums[i]);
             }
         }
         return res;
 
    }
}

1480. 一维数组的动态和(快慢指针,原地修改数组)

class Solution {
    public int[] runningSum(int[] nums) {
        /**
        分析:
        本题可以使用原地修改数组的方法(快慢指针法),降低时间复杂度
         */
         if(nums.length < 2){
             return nums;
         }
         int slow = 0;
         int fast = 1;
         while(fast < nums.length){
             nums[fast] = nums[slow] + nums[fast];
             fast++;
             slow++;
         }
         return nums;

    }
}

42. 接雨水(三指针+双指针)

三指针

class Solution {
    public int trap(int[] height) {
        /**
        分析:
        参考视频题解
        https://www.bilibili.com/video/av375531574/
        运用双指针,不断找出U型结构,其中U型结构可以是左边低,右边高和左边高,右边低的两种类型
        参考文字题解:
        https://leetcode-cn.com/problems/trapping-rain-water/solution/shuang-zhi-zhen-qiu-jie-yu-shui-wen-ti-t-ojil/
        解法一:三指针法,找到最大高度,top指针指向。top区域左右两边分别使用双指针求解。
                top左边区域,根据木桶效应,必须是left > right,才有雨水(这里的left和right代表高度)
                此时的雨水 为 res += left - right,否则 left = right
                右边区域同理,只不过是right - left(木桶效应)
         */
         // 寻找最大高度的值和下标
        int maxValue = 0;
        int maxIndex = 0;        
        for(int i = 0; i < height.length; i++){
            if(height[i] > maxValue){
                maxValue = height[i];
                maxIndex = i;
            }
        }
        int left = height[0];
        int right = 0;
        int sum = 0;
        // 最大下标的左边区域
        for(int i = 1; i < maxIndex; i++){
            right = height[i];
            if(right > left){
                left = right;
            }else{
                sum += left - right;
            }
        }

        right = height[height.length - 1];
        // 最大下标的右边区域
        for(int i = height.length - 2; i > maxIndex; i--){
            left = height[i];
            if(right < left){
                right = left;
            }else{
                sum += right - left;
            }
        }
         return sum;

    }
}

双指针

class Solution {
    public int trap(int[] height) {
        // 使用双指针法
        int left = 0, right = height.length - 1;
        // 定义左边区域的最大高 和右边区域的最大高
        int leftMax = 0, rightMax = 0;
        int res = 0;
        while(left < right){
            leftMax = Math.max(leftMax,height[left]);
            rightMax = Math.max(rightMax,height[right]);
            // 若是height[left] <= height[right]就会出现 左低右高的U形结构,必有雨水
            if(height[left] <= height[right]){
                // 雨水等于 左边最大高 - 当前左边高
                res += leftMax - height[left];
                // 移动左边
                left++;
            }else{
                res += rightMax - height[right];
                right--;
            }
        }
        return res;

    }
}

15. 三数之和(排序+双指针)

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        /**
        分析:
        第一想法是暴力法,三重for循环,结果时间超时了
        第二想法是排序+双指针法,a+b+c = 0,可以看做是a+b = -c
         */
         // 暴力法 时间超时
        //  if(nums.length < 3){
        //      return new ArrayList<>();
        //  }
        //  // 定义结果,这里使用了hashset去重
        //  Set<List<Integer>> res = new HashSet<>();
        //  // 数组排序
        //  Arrays.sort(nums);
        //  // 遍历
        //  for(int i = 0; i < nums.length; i++){
        //      for(int j = i + 1; j < nums.length; j++){
        //          for(int k = j + 1; k < nums.length; k++){
        //              if(nums[i] + nums[j] + nums[k] == 0){
        //                  res.add(Arrays.asList(nums[i],nums[j],nums[k]));
        //              }
        //          }
        //      }
        //  }
        //  return new ArrayList<>(res);

        // 使用排序+双指针法
        if(nums.length < 3){
            return new ArrayList<>();
        }
        Set<List<Integer>> res = new HashSet<>();
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; i++){
            int target = - nums[i];
            // 从 i + 1后面搜索 两数和为 target ,这里使用二分查找
            int left = i + 1;
            int right = nums.length - 1;
            while(left < right){
                int sum = nums[left] + nums[right];
                if( sum == target){
                    res.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    
                    // 下面的循环是为了去重
                    while(left < right && nums[left] == nums[++left]){
                    }
                    while(left < right && nums[right] == nums[--right]){
                    }
                    
                }else if(sum > target){
                    right--;
                }else{
                    left++;
                }
            }
        }
        return new ArrayList<>(res);


    }
}

18. 四数之和(排序+双指针)

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        /**
        分析:
        排序+双指针
        四数之和可以拆成 两数之和的等价形式
         */
         // 使用set进行去重 后来发现使用条件语句去重效率更高!
        //  Set<List<Integer>> res = new HashSet<>();
         List<List<Integer>> res = new ArrayList<>();
         // 排序
         Arrays.sort(nums);
         for(int i = 0; i < nums.length; i++){
             // 使用条件语句去重
             if( i > 0 && nums[i] == nums[i - 1]){
                 continue;
             }
             for(int j = i + 1; j < nums.length; j++){
                 // 使用条件语句去重
                if( j > i + 1 && nums[j] == nums[j - 1]){
                    continue;
                }
                 // 定义部分和
                 int partSum = nums[i] + nums[j];
                 // 定义双指针
                 int left = j + 1;
                 int right = nums.length - 1;
                 while(left < right){
                     int sum = partSum + nums[left] + nums[right];
                     if(sum == target){
                         res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                         // 去重
                         while( left < right && nums[left] == nums[++left]);
                         while( left < right && nums[right] == nums[--right]);
                     }else if(sum > target){
                         right--;
                     }else{
                         left++;
                     }
                 } 
             }
         }
         return res;

    }
}

167. 两数之和 II - 输入有序数组(双指针)

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        // Map<Integer,Integer> map = new HashMap<>();
        // for(int i = 0; i < numbers.length; i++){
        //      if(map.containsKey(target - numbers[i])){
        //          // 这里注意返回的次序
        //          return new int[]{map.get(target-numbers[i]) + 1,i+1};
        //      }
        //      // 储存
        //      map.put(numbers[i],i);
        // }
        // return null;

        // 使用双指针法,这个其实不算二分查找,其实核心思想是理解缩小搜索空间,变为o(n)
       int len = numbers.length;
       int left = 0;
       int right = len - 1;
       // 题目要求,不可以重复使用元素
       while(left < right) {
           int sum = numbers[left] + numbers[right];
           if(sum < target){
               // 说明sum要加大
               left++;
           }else if(sum > target){
               // 说明sum要减小
               right--;
           }else{
               // 相等情况
               return new int[]{left+1,right+1};
           }
       }
       return null;
    }
}

350. 两个数组的交集 II(双指针)

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        // 先排序,在使用双指针法,本题解答很像167. 两数之和 II - 输入有序数组]的双指针解法
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        // 定义结果解
        int[] res = new int[nums1.length];
        // 结果个数
        int count = 0;
        // 双指针,对应两个数组
        int p1,p2;
        p1 = p2 = 0;
        // 但凡有一个指针走到尽头直接over
        while(p1 < nums1.length && p2 < nums2.length){
            if(nums1[p1] > nums2[p2]){
                // p2该努力啦~
                p2++;
            }else if(nums1[p1] < nums2[p2]){
                // p1 该努力啦!
                p1++;
            }else{
                // 匹配成功,两个都一起努力走~
                res[count++] = nums1[p1];
                p1++;
                p2++;
            }
        }
        // 调用Arrays类方法截取数据
        return Arrays.copyOfRange(res,0,count);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值