面试题57. 和为s的两个数字

和为s的两个数字

题目描述

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。


示例:

输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]

输入:nums = [10,26,30,31,47,60], target = 40
输出:[10,30] 或者 [30,10]


提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6

转载来源:力扣(LeetCode)


题目分析

题目划重点递增数组

  • 暴力法,从第一个数开始,选定一个当前数,去和它后面的数相加,如果等于target,就返回,如果大于target,就选定下一个当前数,循环直至找到答案,时间复杂度O(N^2),显然,这里没有把递增数组这一特性用上,时间超限。


    暴力法
  • 优化暴力法,前面的步骤和暴力法一样,但是在“如果大于目标”开始进行了优化,定义了一个全局变量big,当前数+nums[j]如果比target大的话,big就修改为j,下一次内层循环就到big结束,不用循环到nums.length,为什么可以这么做呢,因为数组是有序的,如果前面第i个数加第j个数比target大,那么第i+1个数加第j个数肯定比target大,所有下一次循环的终点是j-1;但是优化暴力法原理上还是双层循环,时间复杂度是O(N^2),尝试了一下,还是时间超限。


    优化暴力法
  • 两头开工法(双指针),优化暴力法是从头加到尾,并尾部往前推,双指针法是头指针往后退,尾指针往前推,思想和优化暴力法的思想是差不多的,一开始头指针为0,尾指针为nums.length - 1
    . 如果两数相加等于target,直接返回
    · 如果两数相加大于target,因为头指针是有可能为答案的数里最小的数,那么头指针往后的数加尾指针都会大于target,尾指针就可以舍弃(不可能是答案),尾指针往前推
    . 如果两数相加小于target,因为尾指针是有可能为答案的数里最大的数,那么尾指针往前的数加头指针都会小于target,头指针就可以舍弃(不可能为答案),头指针往后推

 双指针法通过循环不断的缩小有可能为答案的范围,每一次计算都可以将两极不可能为答案的数字排除掉,因为答案是肯定存在的,所以最多只要遍历一遍就可以得到答案,时间复杂度是O(N),显然,AC了!


双指针法
fun twoSum(nums: IntArray, target: Int): IntArray {
//      优化暴力法
        var big = nums.size
        for (i in nums.indices) {
            for (j in 0 until big) {
                if (nums[i] + nums[j] == target)
                    return intArrayOf(nums[i], nums[j])
                if (nums[i] + nums[j] > target) {
                    big = j
                    break
                }
            }
        }
        
//      双指针法
        var head = 0
        var tail = nums.size - 1
        while (head != tail){
            if(nums[head] + nums[tail] == target)
                return intArrayOf(nums[head],nums[tail])
            if(nums[head] + nums[tail] > target)
                tail--
            else
                head++
        }
        return intArrayOf(0)
    }

代码文件


你可能感兴趣的:(面试题57. 和为s的两个数字)