三路快排与对撞指针

这篇博客介绍了三路快排的优势,它减少了重复元素的操作次数。接着,讨论了如何在LeetCode的167号问题中利用三路快排的思想,以及对撞指针策略来解决有序数组中寻找目标和的问题。文章提供了两种不同的解决方案,一种是暴力解法,另一种是利用二分搜索。最后,详细解释了对撞指针如何有效地缩小区间并找到答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.三路快排对比快速排序的优势

相对于快速排序,三路快排的优势是在于能够减少重复元素操作次数

2.三路快排主要的思路

定义lt,gt两个初始变量,[lt,gt]表示该区间的元素等于v

通过遍历每个元素得到lt,gt的最终变量值

3.代码设计

    private static void quick(Comparable[] nums, int l, int r){

        if (l >= r)
            return;
        Comparable v = nums[l];
        int lt = l;
        int gt = r;
        // [lt,gt]代表v == e
        for (int i = lt ; i <= gt; i ++){
            if (v.compareTo(nums[i]) > 0){
                if (i != lt)
                    swap(nums, i, lt);
                lt ++;
            }
            else if(v.compareTo(nums[i]) < 0){
                swap(nums, i, gt);
                gt --;
                i --;
            }
        }


        quick(nums, l, lt - 1);
        quick(nums, gt + 1, r);

    }

4.

在Leetcode的167号问题

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2

说明:

  • 返回的下标值(index1 和 index2)不是从零开始的。
  • 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

示例:

输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

解答1:这个问题我们首先想到的是暴利解法,通过两层的遍历来解决问题,这样时间复杂度级别为O(N^2)

解答2::我们想到这个数组是个有序的数组,我们可以遍历每个元素,然后通过二分搜索来找到与之对应的解,这样时间复杂度级别是O(NlogN)

代码如下

class Solution {
     public  int[] twoSum(int[] numbers, int target) {

        int[] res = new int[2];
        for (int i = 0; i < numbers.length; i ++){
            int j = search(numbers, i + 1, numbers.length - 1 , target - numbers[i]);
            if (numbers[i] + numbers[j] == target){
                res[0] = i + 1;
                res[1] = j + 1;
                break;
            }
        }
        return res;
    }
    
    private int search(int[] numbers, int l , int r, int res){
        if (l >= r){
            return l;
        }
        int mid = (l + r) / 2;
        if (numbers[mid] == res)
            return mid;
        else if (numbers[mid] <= res)
            return search(numbers,mid + 1, r, res);
        else 
            return search(numbers, l, mid - 1, res);
    }
}

解答三:考虑到这个数组是有序数组,我们可以采用对撞指针来不停的缩小区间来找到最后答案

             定义两个初始变量分别指向数组头部和尾部,然后进行遍历操作,每一层遍历缩小一个单位(如果两个值大于target,尾              部缩小一个单位,反之头部增加一个单位),直到找到最后的答案

            为什么会这样进行操作呢?

           原因如下:当(当前区间)最小值加上最大值都大于target,其他值加上最大值必然大于target,所以尾部可以缩小区间 ,反之亦然

代码如下:

class Solution {
   public  int[] twoSum(int[] numbers, int target) {
        int res[] = new int[2];
        int n = 0;
        int m = numbers.length - 1;
        for (int i = 0; i < numbers.length; i ++){
            if (numbers[n] + numbers[m] == target){
                res[0] = n + 1;
                res[1] = m + 1;
                break;
            }
            else if (numbers[n] + numbers[m] < target){
                n ++;
            }
            else {
                m --;
            }
        }
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值