两数之和(加拓展延伸)

81 阅读2分钟

题:

//给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 
//
// 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 
//
// 你可以按任意顺序返回答案。 
//
// 
//
// 示例 1: 
//
//输入:nums = [2,7,11,15], target = 9
//输出:[0,1]
//解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
// 
//
// 示例 2: 
//
//输入:nums = [3,2,4], target = 6
//输出:[1,2]
// 
//
// 示例 3: 
//
//输入:nums = [3,3], target = 6
//输出:[0,1]
// 
//
// 
//
// 提示: 
//
// 
// 2 <= nums.length <= 10⁴ 
// -10⁹ <= nums[i] <= 10⁹ 
// -10⁹ <= target <= 10⁹ 
// 只会存在一个有效答案 
// 
//
// 
//
// 进阶:你可以想出一个时间复杂度小于 O(n²) 的算法吗? 
//
// Related Topics 数组 哈希表 👍 16687 👎 0

package questions.leetcode.editor.cn

fun main() {
    val solution = TwoSum1.Solution()
    val result = solution.twoSum(intArrayOf(2, 7, 9, 11), 9)
    println(result.asList())
}

class TwoSum1 {

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        fun twoSum(nums: IntArray, target: Int): IntArray {
            if (nums.size < 2) {
                return intArrayOf(0, 0)
            }
            val map = HashMap<Int, Int>()
            for (i in nums.indices) {
                val temp = target - nums[i]
                if (map.containsKey(temp)) {
                    return intArrayOf(map[temp]!!, i)
                } else {
                    map[nums[i]] = i
                }
            }
            return intArrayOf(0, 0)
        }
    }
//leetcode submit region end(Prohibit modification and deletion)


}

解析:

这种两个数配对的题目都可以用 Map 来解决,主要是用的Map查找效率高的特性,仅仅由于 Array 的查找效率不如 Map 而已。

将遍历过的数据存放到 Map 里面,并在遍历后面的数的时候,在 Map 里查询是否存在可以配对的数据

扩展

题目说找出唯一的答案即可

现在改为有序数组,找出所有的答案(前提是数组里至少有一个答案)

// value:   -1  1   1   4   4   5   6   7   10  12  14  21
// index:   0	1   2	3   4	5   6   7   8   9   10  11
// target = 9
// 输出 `List<IntArray>` 为{(0,8), (3,5), (4,5)} (顺序可乱)
// 由于 Map 有去重的特性,如果我们再用上述方法,就会在遍历到下标为 4 的 4 的时候,将 下标原本为 3 的 4 覆盖 ,然后失去 (3,5) 这个对

// 可以在这里停下思考一下

// 所以我们需要一个不去重,但是可以和 HashMap 拥有同级别的查找效率的数据结构
// 而 HashMap 是用哈希值来计算数组索引,然后进行红黑树查找的,
// 所以要么我们自己重写 HashMap 要么想别的办法

package questions.leetcode.editor.cn

fun main() {
    val solution = TwoSum1Extension.Solution()
    val result = solution.twoSum(intArrayOf(-1, 1, 1, 4, 4, 5, 6, 7, 10, 12, 14, 21), 9)
    for (t in result) {
        println("(${t[0]},${t[1]})")
    }
}

class TwoSum1Extension {

    // 计算有序数组的  两数之和结果
    class Solution {

        /**
         * 分别寻找两个数,小于 target/2 ,并且最接近的 target/2 的数 以及 大于 target/2 ,并且最接近的 target/2 的数
         * 例如:1,2,3,4,5,5,6,7 target = 9,则这两个数为 4 和 5,
         * 例如:-3,-1,0,9,11 target = -1, 则这两个数为 -1 和 0
         * 找到这两个数分别向两边寻找
         */
        fun twoSum(orderedNums: IntArray, target: Int): List<IntArray> {
            if (orderedNums.size < 2) {
                return emptyList()
            }

            val result = ArrayList<IntArray>()
            var closeSmaller = 0
            var closeBigger = 0

            // 如果最小的数小于 target/2 则不存在这样的数对之和等于 target (因为最小的数 ×2 已经大于 target 了)
            if ((target / 2) < orderedNums[closeSmaller]) {
                return emptyList()
            }
            for (i in orderedNums.indices) {
                if (orderedNums[i] < target / 2 + 1) {
                    closeSmaller = i
                } else {
                    break
                }
            }
            if (closeSmaller < orderedNums.size - 1) {
                closeBigger = closeSmaller + 1
            } else {
                return emptyList()
            }

            if (closeSmaller <= orderedNums.size / 2 + 1) {
                for (i in closeSmaller downTo 0) {
                    for (j in closeBigger until orderedNums.size) {
                        when {
                            orderedNums[i] + orderedNums[j] == target -> {
                                result.add(intArrayOf(i, j))
                            }

                            orderedNums[i] + orderedNums[j] > target -> {
                                break
                            }
                        }
                    }
                }
            }


            return result
        }
    }
}

时间复杂度为 O(n2)O(n^2)