[算法] 使用“复杂”的数据结构降低时间复杂度

来源:互联网 发布:电陶炉 知乎 编辑:程序博客网 时间:2024/06/03 16:41

Leetcode 1: Two Sum

问题描述

给定一个整数数组和一个目标数,返回两个下标,使数组中这两个下标所代表的数字之和等于目标数。
你可以认为每组输入有且仅有一个正解,除此之外,两个下标不应当相等。

例子:
给定一数组nums = [2, 7, 11, 15],目标数target = 9
因为nums[0] + nums[1] = 2 + 7 = 9 = target,所以最后返回[0, 1]。

解题思路

显然的,本题最直接明了的方式就是暴力循环两个数组,依次算出所有和,并判定它是否与目标数相等,可以写出:

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        vector<int> ret { 0, 1 };        for (int i = 0; i < nums.size(); i++) {            ret[0] = i;            for (int j = i + 1; j < nums.size(); j++) {                if (nums[i] + nums[j] == target) {                    ret[1] = j;                    return ret;                }            }        }    }};

这里我们发现,已知nums[i]和target,nums[j]可以取的值是固定的,所以可以不必每次都做加法运算,将内循环改为:

            int tar = target - nums[i];            ret[0] = i;            for (int j = i + 1; j < nums.size(); j++) {                if (nums[j] == tar) {                    ret[1] = j;                    return ret;                }            }

但这里只是改进了常数级别的时间复杂度,有没有什么方法只遍历数组一次就解决呢?如果想要只遍历一次就解决,主要的矛盾还是在如何不必循环就快速的查询出target - nums[i]是否在之前存在过。这里我使用了map作为查询的方法。

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        map<int, int> exist;        vector<int> ret { 0, 1 };        for (int i = 0; i < nums.size(); i++) {             int comp = target - nums[i];            if (exist[comp] != 0) {                ret[0] = exist[comp] - 1;                ret[1] = i;                return ret;            }            exist[nums[i]] = i + 1;        }    }};

果然,改进之后,时间复杂度大幅度降低。通过时间由166ms降低为9ms。

原创粉丝点击