排序数组中的两个数字之和

题目:
输入一个递增排序的数组和一个值k,请问如何在数组中找出两个和为k的数字并返回它们的下标?假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。例如,输入数组[1,2,4,6,10],k的值为8,数组中的数组2与6的和为8,它们的下标分别为1和3.

解法一:

先在数组中固定一个数字,再依次判断数组中其余数字与它的和是否为k。
假设扫描到数字i,如果数组中存在另一个数字k-i,那么就找到了一对和为k的数字。
由于数组是递增排序的,因此可以用二分查找在数组中搜索k-i。

代码如下:

    public int[] TwoSum1(int[] arrays, int k)
    {   int a=0;
        int i=0;
        for (;i<arrays.length;i++)
        {
            a = search(arrays, k-arrays[i]);//二分查找k-i
            if(a != -1)
                break;
        }
        if (a==-1)//如果找不到符合的数字元素,打印提示信息并退出程序
        {
            System.out.println("找不到数字");
            System.exit(0);
        }
        return new int[]{i, a};
    }
    /*二分查找方法*/
    public static int search(int[] arr, int key) {
        int start = 0;
        int end = arr.length - 1;
        while (start <= end) {
            int middle = (start + end) / 2;
            if (key < arr[middle]) {
                end = middle - 1;
            } else if (key > arr[middle]) {
                start = middle + 1;
            } else {
                return middle;
            }
        }
        return -1;
    }

二分查找的时间复杂度是O(logn),因此优化之后的解法的时间复杂度是O(nlogn)。

解法二:

先将数组中的所有数字都放入一个哈希表,然后逐一扫描数组中的每个数字。假设扫描到数字i,如果哈希表中存在另一个数字(k-i),那么就找到了一对和为k的数字。

代码如下:

    public int[] TwoSum2(int[] arrays, int k)
    {
        Map<Integer, Integer> hashmap = new HashMap<>();/*创建一个哈希表*/
        for (int i=0; i<arrays.length;i++){
            hashmap.put(arrays[i], i);/*将数组中所有元素都放进哈希表中*/
        }
        for (int j=0; j<arrays.length;j++)
        {
            if (hashmap.containsKey(k-arrays[j])){//如果哈希表中存在另一个数字(k-j)
                return new int[]{j,hashmap.get(k-arrays[j])};/*那么便意味着找到了一对和为k的数,将其返回*/
            }
        }
        return new int[0];
    }

判断哈希表中是否存在一个数字的时间复杂度是O(1),所以此解法的时间复杂度是O(n),空间复杂度也是O(n).

解法三:

用两个指针P1和P2分别指向数组中的两个数字。指针P1初始化指向数组的第1个(下标为0的)数字,指针P2初始化指向数组的最后一个数字。
①如果指针P1和P2指向的两个数字之和等于输入的k,那么就找到了符合条件的两个数字。
② 如果指针P1和P2指向的两个数字之和小于k,那么我们希望两个数字的和再大一点。由于数组已经排好序,因此可以考虑把指针P1向右移动。因为在排序数组中右边的数字要大一些,所以两个数字的和也要大一些,这样就有可能等于输入的数字k。
③同样,当两个数字的和大于输入的数字k时,可以把指针P2向左移动,因为在排序数组中左边的数字要小一些。

代码如下

    public int[] TwoSum(int[] arrays, int k)
    {
        int p1=0;
        int p2=arrays.length-1;
        while (p1<p2 && arrays[p1]+arrays[p2] != k)//左指针指向数组下标小于右指针指向数组下标
        {                                          //且两下标表示的数组元素和不等于k
            if(arrays[p1]+arrays[p2]>k)//如果两数之和小于k
            {
                p2 = p2-1;//右指针左移一位
            }else
                {
                    p1 = p1 + 1;//左指针右移一位
                }
        }
    return new int[]{p1,p2};//返回一个存储两个指针下标的数组
    }

由于上述代码中只有一个while循环,循环执行的次数最多等于数组的长度,因此这种思路的时间复杂度是O(n)。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

回家种蜜柚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值