立刻开始复习永远不晚 力扣刷题笔记 1.两数之和

如题

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例: 给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

C++

1.暴力解

遍历两遍数组 寻找结果

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        bool notFound = true;
        int i=-1;
        int j=0;
        while(notFound == true)
        {// 找到时候跳出
            i++;
            j=0;
            if(i==nums.size())
            {//遍历结束跳出
                std::cout << "not found";
                notFound = false;
            }            
            else 
            {
                for(j; j<nums.size();j++)
                {
                    if(j!=i)
                    {
                        if((nums[i]+nums[j])== target)
                        {   notFound = false;
                            break;
                        }
                    }
                }
            }
        }
        vector<int> answer;
        answer.push_back(i);
        answer.push_back(j);
        return answer;
    }
};

代码执行结果
执行用时 : 396 ms 在所有 C++ 提交中击败了 13.36% 的用户
内存消耗 : 9.2 MB , 在所有 C++ 提交中击败了 79.86% 的用户

存在的问题: while 循环跳出优化 / for循环跳出优化

暴力法优化 1:

优化循环的结构和跳出条件

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        bool notFound = true;
        int i=-1;
        int j=0;
        while(notFound == true && i!=nums.size())
        {
            i++;
            //j从i+1 的位置开始可以避免重复计算 例如避免计算 i=0 j=1 和 i=1 j=1 的情况
            for(j=i+1; j<nums.size();j++)
            {
                if((nums[i]+nums[j])== target)
                {   
                    notFound = false;
                    break;
                }
            }
        
        }
        vector<int> answer;
        answer.push_back(i);
        answer.push_back(j);
        return answer;
    }
};

执行结果:
执行用时 : 244 ms, 在所有 C++ 提交中击败了 31.21% 的用户
内存消耗 : 9.1 MB , 在所有 C++ 提交中击败了 96.52% 的用户

暴力法小优化2:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        bool notFound = true;
        vector<int> answer;
        int i=-1;
        int j=0;
        while(notFound == true && i!=nums.size())
        {
            i++;
            for(j=i+1; j<nums.size();j++)
            {
                if((nums[i]+nums[j])== target)
                {   
                    notFound = false;
                    answer.push_back(i);//避免再一次读取i/j的值
                    answer.push_back(j);
                    break;
                }
            }
        }
        return answer;
    }
};

代码执行结果
执行用时 : 184 ms, 在所有 C++ 提交中击败了48.23%的用户
内存消耗 : 9.2 MB , 在所有 C++ 提交中击败了 91.94%的用户

暴力法优化3

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    // 优化循环不设置 flag 同时减少运行时间和内存消耗
        for(int i = 0; i<nums.size();i++)
        {
            for(int j=i+1; j<nums.size();j++)
            {
                if((nums[i]+nums[j])== target)
                {   
                    return {i,j}; // 直接返回结果 减少内存消耗
                }
            }   
        }
        throw "Not found!"; // 使用Exception 提高代码的健壮性
    }
};

代码执行结果
执行用时 : 172 ms, 在所有 C++ 提交中击败了49.52%的用户
内存消耗 : 9.1 MB , 在所有 C++ 提交中击败了92.59%的用户

另外一个小的优化: 1. 使用 一个常数代替 num.size(), 牺牲内存获取执行上的一点点速度
这差不多是暴力法能做到的极致了

2.使用哈希表unordered_map

map类和 hashmap 的查找效率比较高,可以换成这两种

c++ map类参考资料 https://blog.csdn.net/xywlpo/article/details/6545594
c++ unordered_map (哈希表) 类参考资料 https://zh.cppreference.com/w/cpp/container/unordered_map


class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> numsHash;
        for(int i = 0 ; i < nums.size() ; i ++){
            numsHash[nums[i]] = i;
        } //初始化hash表
        for(int i = 0 ; i < nums.size() ; i++)
        {
            auto index = numsHash.find(target-nums[i]);//返回查找到元素的iterator,如未查找到,返回end() 疑问: 寻找的是键还是值?
            if(index!=numsHash.end() && index->second!=i)
            {
                return {i,index->second}; //       
            }
        }
        return {0,0};
    }
};

该方法有一遍初始化 O(n) 和一遍hash的查找O(1) 时间复杂度低,但是空间复杂度高

代码执行结果
执行用时 : 8ms, 在所有 C++ 提交中击败了98.71%的用户
内存消耗 : 10.4 MB , 在所有 C++ 提交中击败了16.92%的用户

hash法优化:

范例

执行用时为 4 ms 的
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
     //时间复杂度n,空间复杂度n
        // 还是使用哈希表,但不在一开始就insert,而是在迭代过程中insert,只需查找一次哈希表
        map<int, int> myMap;
        // 初始化一个大小是2,值为-1的vector容器
        vector<int> result(2, -1);
        for (int i = 0; i < nums.size(); i++) {
            // 前面的值在哈希表中,相当于从后往前找,所以这样命名
            int secondNum = nums[i];
            int firstNum = target - secondNum;
            // 当前值nums[i]还不在哈希表中,不用判断目标值是否本身
            if (myMap.count(firstNum) > 0) {
                result[0] = myMap[firstNum];
                result[1] = i;
                break;
            }
            
            // 没找到就放入哈希表中
            myMap.insert(make_pair(secondNum, i));
        }            
        return result;
    }
};

在我自己基础上优化的代码
有个问题是根据结果来看,这段代码的优化效果为负 XD
执行用时 :12 ms, 在所有 C++ 提交中击败了92.50%的用户
内存消耗 :10.1 MB, 在所有 C++ 提交中击败了35.89%的用户

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> numsHash;
        for(int i = 0 ; i < nums.size() ; i++)
        {
            auto index = numsHash.find(target-nums[i]);//返回查找到元素的iterator,如未查找到,返回end() 疑问: 寻找的是键还是值?
            if(index==numsHash.end())
            {
                numsHash[nums[i]]=i; // 没找到
            }
            else if(index->second!=i)
            {
                return {i,index->second}; //返回位置    
            }
            else{
                numsHash[nums[i]]=i; // 找到了,但是是同一个值
            }
        }
        return {0,0};
    }
};

你可能感兴趣的:(立刻开始复习永远不晚 力扣刷题笔记 1.两数之和)