LeetCode 167:两数之和 II (有序数组)

LeetCode 167
题目:
在这里插入图片描述

思路:

①先确定一个数nums[i]
②找另一个数target-nums[i]
(有序时则想到二分法!)

方法一:二分查找

数组升序排列 是使用二分查找的前提!
用for遍历数组每个数num[i],
每一轮使用二分查找 找是否存在 target-numbers[i]的数
注意for中 i 还是从0开始,数组索引从 i+1 开始!
由于数组索引从1开始算,所以二分查找中left =i+1 ,每查完一个nums[i],待查元素num[I]依次减少

注意

  1. 二分法的while条件必须是 left <= right 而不是 left < right
  2. 返回的是 i+1, mid+1
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        for(int i=0;i<numbers.length;i++){

            // 二分法, 由nums[i], 找是否存在 val=target-nums[i]
            int val=target-numbers[i]; // 二分法需要找的值 !
            int left=i+1; // 索引从1开始
            int right=numbers.length-1;
            while(left<=right){   // 注意是left<=right ! left>right才跳出while
                int mid=left+(right-left)/2;
                if(numbers[mid]==val){
                    return new int[]{i+1,mid+1};
                }else if(val>numbers[mid]){
                    left=mid+1;
                }else if(val<numbers[mid]){
                    right=mid-1;
                }
            }
        }
        return new int[]{0,0};
    }
}

注意 :循环判断条件是 while(left <= right)

时间复杂度:O(nlogn),其中 n 是数组的长度。需要遍历数组一次确定第一个数,时间复杂度是 O(n)O(n),寻找第二个数使用二分查找,时间复杂度是 O(logn),因此总时间复杂度是 O(nlogn)。

空间复杂度:O(1)O(1)。

方法二:双指针

只要数组有序,就应该想到双指针技巧。这道题的解法有点类似二分查找,通过调节 left 和 right 就可以调整 搜索范围

class Solution {
    public int[] twoSum(int[] numbers, int target) {
    // 双指针 相向而行
        int left=0;
        int right=numbers.length-1;
        while(left<right){
            int sum=numbers[left]+numbers[right];
            if(sum>target){
                right--;
            }else if(sum<target){
                left++;
            }else if(sum==target){
                return new int[]{left+1,right+1}; // 下标1开始,要+1
            }
        }
        return new int[0];
    }
}

时间复杂度::O(n),其中 nn 是数组的长度。两个指针移动的总次数最多为 nn 次。

空间复杂度:O(1)

方法三:HashMap

和普通的两数之和使用同样的方法,没有利用到题目中数组有序的条件;
先确定循环的数m,再遍历map去寻找数字k,并返回索引;

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int n=numbers.length;
        Map<Integer,Integer> h=new HashMap<>();
        for(int i=0;i<n;i++){
            // 确定当前循环的数 m
            int m=numbers[i];
            // 确定要找的数 k
            int k=target-m;
            if(h.containsKey(k)){
                return new int[]{h.get(k)+1,i+1};
            }else{
                // 存入map
                h.put(m,i);
            }
        }
        return new int[2];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值