10. <tag-数组和双指针(左右指针)>-lt.344-反转字符串 + lt.16-最接近的三数之和 + lt.349-两个数组的交集

lt.344-反转字符串

[案例需求]
在这里插入图片描述

[思路分析]

  • 原地逆转
    在这里插入图片描述

[代码实现]

class Solution {
    
    
    public void reverseString(char[] s) {
    
    
        //左右指针法
        int L = 0;
        int R = s.length - 1;
        char temp = ' ';
        while(L < R){
    
    
            temp  = s[L];
            s[L] = s[R];
            s[R] = temp;

            ++L;
            --R;
        }
    }
}

lt. 16-最接近的三数之和

[案例需求]
在这里插入图片描述

[思路分析]

  • 前面我们说过, 双指针一般用于有序的数组, 这道题的数组虽然是无序的, 但是由于题目中并没有对时间复杂度做出限定. 我们大可以先把数组排序, 然后利用左右指针遍历后两个加数.
  • 题目要求是与target值差距最小的三数之和, 那我们只需设置一个minSum存储与target差距较小的三数之和, 通过跟每次循环中的三数之和比较, 来达到不断更新较小值直到最优的目的;
  • 具体思路如下:
    1. 利用数组遍历第一个加数, 每一次遍历就是固定一个加数, 使用左右指针寻找后两个加数的过程;
    2. nums[i] + nums[L] + nums[R] == target, 我们直接返回就好;
    3. nums[i] + nums[L] + nums[R] < target. 由于已经排序, 直接移动L指针;
    4. nums[i] + nums[L] + nums[R] > target. 由于已经排序, 直接移动R指针;
    5. 上面第3或第4步执行之后. 就立刻比较当前的三数之和和target的差值的绝对值, 更新较小值;

[代码实现]

class Solution {
    
    
    public int threeSumClosest(int[] nums, int target) {
    
    
        //遍历第一个数,  后两个加数用指针, 
        //三数之和不断更新, 何时: 与target的差值绝对值最小;
        // 绝对值方法 Math.abs();

        int left,right = 0;
        int threeSum = 0;
        int minSum = nums[0] + nums[1] + nums[2];

        Arrays.sort(nums);

        for(int i = 0; i < nums.length; i++){
    
    
            left = i + 1;
            right = nums.length - 1;

            

            while(left < right){
    
    

                threeSum = nums[i] + nums[left] + nums[right];

                if(threeSum > target){
    
    
                    --right;
                }else if(threeSum < target){
    
    
                    ++left;
                }else{
    
    
                    return threeSum;
                }
				//比较每次遍历时, 三数之和与target差值的绝对值大小, 更新较小的值
                if(Math.abs(threeSum - target) < Math.abs(minSum - target))
                    minSum = threeSum;
            }
        }
        return minSum;
    }
}

lt.349-两个数组的交集

[案例需求]
在这里插入图片描述

[思路分析]

  1. 常规思路就是对两个数组分别排序后, 设置两个指针分别指向两个数组的0号索引处, 循环结束条件就是指针到达其中任一数组的末尾;
  2. 又因为要求我们输出结果中每个元素是唯一的, 所以, 我们可以把两数组的交集存储在Set集合中.
  3. 最后把Set集合转为int[]. 注意这里转换的方法: set集合.stream().mapToInt(Integer::valueOf).toArray();
  4. 思路很简单, 效率也很低;

[代码实现]

public int[] intersection(int[] nums1, int[] nums2) {
    
    
        //设置set存放交集, 结果把set转为int[]并返回

        Arrays.sort(nums1);
        Arrays.sort(nums2);

        Set<Integer> resSet = new HashSet<Integer>();

        int left = 0;
        int right = 0;

        while(left < nums1.length && right < nums2.length){
    
    
            if(nums1[left] < nums2[right]){
    
    
                left++;
            }else if(nums1[left] > nums2[right]){
    
    
                right++;
            }else{
    
    
                resSet.add(nums1[left]);
                left++;
                right++;
            }
        }

        return  resSet.stream().mapToInt(Integer::valueOf).toArray();
}

优化版本:

  • 我们把对两个数组的排序砍掉, 把前一个数组nums1, 遍历存储到Set1中,
  • 而对于nums2, 我们对nums2进行遍历, 通过set.contains(obj) 判断nums2中的数是否跟set集合中的一致;
  • 如果一致的话, 说明是重叠元素, 在这里我们还是新建一个Set2来存储重叠元素(为什么还是用集合存, 因为重叠元素不定长度)
  • 新建结果数组res, 遍历Set2, 依次赋值给数组中的对应索引, 返回结果数组即可;
class Solution {
    
    
    public int[] intersection(int[] nums1, int[] nums2) {
    
    
    if(nums1.length == 0 || nums2.length == 0) return new int[]{
    
    };

    Set<Integer> set1 = new HashSet<>();
    Set<Integer> set2 = new HashSet<>();
    for(int i : nums1){
    
    
        set1.add(i);
    }

     for(int i : nums2){
    
    
         if(set1.contains(i)){
    
    
             set2.add(i);
         }
     }   
    
    int[] res = new int[set2.size()];
    int j = 0;
    for(int i : set2){
    
    
        res[j++] = i;
    }

	//通过遍历集合, 把数值赋值给数组, 要比上面的 xx.stream().mapToInt(Integer::valueOf).toArray() 快得多
     return  res;
    }
}

比上面排序+双指针要快了 3~4ms.
在这里插入图片描述

Je suppose que tu aimes

Origine blog.csdn.net/nmsLLCSDN/article/details/121510560
conseillé
Classement