leetcode刷题笔记(一、两数之和)

一直都想刷leetcode了,但是以前只会c语言,用c语言刷太辛苦了,现在又开了一个副本,学了c++,c++有内置的STL之后,刷起leetcode会简单一点吧,但是总感觉自己的算法思维不够,希望刷刷leetcode会提升一下自己吧,这一个专题,就是记录着刷leetcode的过程,也希望通过这个专题来倒逼自己刷leetcode,也留点东西做个回忆。

1.1 题目

我们英文题目和中文题目都来,顺便学学英文。

1.1.1 Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

1.1.2 两数之和

给定一个整数数组 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

说实话,还是中文看起来比较懂,英文题目就当做一个尝试。

1.2 暴力解法

说实话,刚看到题目,也就只能想到遍历这种方式,没有大神想的那么多,也可能冒泡影响比较深,老是想着两层for循环,先写写程序试试吧。

1.2.1 程序

/*
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,
并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
*/

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> temp;
        //1.暴力破解法
        int i = 0, j = 0;

        for(i=0; i<nums.size(); i++) {
            for(j=i+1; j<nums.size(); j++) {
                if(nums[i] + nums[j] == target) {
                    cout << "找到了符合的,填充到vector中" << endl;
                    cout << nums[i] << "  "<< nums[j] << endl;
                    temp.push_back(i);
                    temp.push_back(j);
                }
            } 
        }
        return temp;
    }
};


int main(int argc, char** argv)
{
    int array[] = {2, 7, 11, 15};
    vector<int> nums(array, array+sizeof(array)/sizeof(int));
    int target = 9;

    Solution p;
    p.twoSum(nums, target);

    return 0;
}

1.2.2 解析

暴力解法,逻辑应该很清晰了,两边for,把数组中的任意两个数都组合起来,再跟目标值target比较,如果相等,说明成功了,如果不等,继续循环。

1.2.3 复杂度分析

  • 时间复杂度:O(n2)
    对于每个元素,我们试图通过遍历数组的其余部分来寻找它所对应的目标元素,这将耗费 O(n) 的时间。因此时间复杂度为O(n2)。

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

1.3 两遍哈希表

这种实现我也不懂,是看了解题方法之后,才明白大神就是厉害,竟然看到了,那就自己实现实现了,好记性不如烂笔头,实现一遍总比看着好。

1.3.1 程序

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> temp;

        int i = 0, j = 0;
        //1.暴力破解法
        #if 0
        for(i=0; i<nums.size(); i++) {
            for(j=i+1; j<nums.size(); j++) {
                if(nums[i] + nums[j] == target) {
                    cout << "找到了符合的,填充到vector中" << endl;
                    cout << nums[i] << "  "<< nums[j] << endl;
                    temp.push_back(i);
                    temp.push_back(j);
                }
            } 
        }
        #endif

        //2.两边哈希表  
        //unordered_map 是c++的哈希表
        unordered_map<int, int> hash_map;

        //往哈希表填值
        for(i=0; i<nums.size(); i++) {
            //hash_map.insert(make_pair<int, int>(1, 1));
            hash_map.insert(pair<int, int>(nums[i], i));
        }

        //遍历vector容器,查看哪一个匹配
        for(i=0; i<nums.size(); i++) {
            cout << target - nums[i] << endl;
            unordered_map<int,int>::const_iterator got = hash_map.find(target - nums[i]);
            if(got != hash_map.end() && i != got->second) { 
            	//这个需要注意不能匹配自己
                cout << i << "  " << got->second << endl;
                temp.push_back(i);
                temp.push_back(got->second);
                return temp;
            }
        }
        return temp;
    }
};

1.3.2 解析

这个也比较简单,由空间换时间的思想,取数据最快的还是哈希表,因为哈希表取一个数据时间是O(1),但是也适当的增加了内存。

整体思想:第一遍遍历是把vector的值保存到哈希表中,第二次遍历是,再从新从vector中取出数据,然后跟目标值相减,然后利用这个差,到哈希表中取数据,如果没有,说明没有匹配,如果有,说明匹配了。

1.3.3 复杂度分析

  • 时间复杂度:O(n)
    我们把包含有 n 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1) ,所以时间复杂度为 O(n)。

  • 空间复杂度:O(n)
    所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n 个元素。

1.4 一遍哈希表

1.4.1 程序

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> temp;

        int i = 0, j = 0;
        //1.暴力破解法
        #if 0
        for(i=0; i<nums.size(); i++) {
            for(j=i+1; j<nums.size(); j++) {
                if(nums[i] + nums[j] == target) {
                    cout << "找到了符合的,填充到vector中" << endl;
                    cout << nums[i] << "  "<< nums[j] << endl;
                    temp.push_back(i);
                    temp.push_back(j);
                }
            } 
        }
        #endif

        //2.两遍哈希表  
        #if 0
        //unordered_map 是c++的哈希表
        unordered_map<int, int> hash_map;

        //往哈希表填值
        for(i=0; i<nums.size(); i++) {
            //hash_map.insert(make_pair<int, int>(1, 1));
            hash_map.insert(pair<int, int>(nums[i], i));
        }

        //遍历vector容器,查看哪一个匹配
        for(i=0; i<nums.size(); i++) {
            cout << target - nums[i] << endl;
            unordered_map<int,int>::const_iterator got = hash_map.find(target - nums[i]);
            if(got != hash_map.end() && i != got->second) {
                cout << i << "  " << got->second << endl;
                temp.push_back(i);
                temp.push_back(got->second);
                return temp;
            }
        }
        #endif 

        //3.一遍哈希表 
        unordered_map<int, int> hash_map;

        for(i=0; i<nums.size(); i++) {
            cout << target - nums[i] << endl;
            //先查找哈希表中是否有对应的值
            unordered_map<int,int>::const_iterator got = hash_map.find(target - nums[i]);
            if(got != hash_map.end()) {
                cout << i << "  " << got->second << endl;
                temp.push_back(i);
                temp.push_back(got->second);
                return temp;
            }

            //没有找到,填充数据到哈希表
            hash_map.insert(pair<int, int>(nums[i], i));   
        }

        return temp;
    }
};

1.4.2 解析

这个一遍哈希表,可能不太理解,确实也是,经过昨晚想了一晚,好像有点想通了,先写一写:
举例:
数组元素:2,7,4,11
然后按照第二中解法匹配:

2 - 2 2 - 7 2 - 4 2 - 11
7 - 2 7 - 7 7 - 4 7 - 11
4 - 2 4 - 7 4 - 4 4 - 11
11 - 2 11 - 7 11 - 4 11 - 11

上面的表格,是列出了所有匹配情况,是不是眼尖的朋友,就有看到对称的关系,没错,其实这个表格是对角线对称的,也就是起码两个查找重复了,还有两个下标一样,也要去掉,所以我们把重复的去掉:

2 - 2 2 - 7 2 - 4 2 - 11
7 - 2 7 - 7 7 - 4 7 - 11
4 - 2 4 - 7 4 - 4 4 - 11
11 - 2 11 - 7 11 - 4 11 - 11

这样去掉了之后,是不是发现了一些神奇的现象:
按照这样的表格,就支持一边插入一遍匹配。

  1. 插入2到哈希表中,然后匹配,没匹配到。
  2. 插入7到哈希表中,然后匹配(7-2 )。
  3. 插入4到哈希表中,然后匹配(4-2、4-7)。
  4. 插入11到哈希表中,然后匹配(11-2、 11-7 、11-4)

是不是就把表格中的都匹配上了。

1.4.3 复杂度分析

  • 时间复杂度:O(n)
    我们只遍历了包含有 n 个元素的列表一次。在表中进行的每次查找只花费 O(1) 的时间。

  • 空间复杂度:O(n)
    所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 n 个元素。

我也不知道这种想法对不对,如有不对,欢迎讨论,学习嘛,就是一起讨论。

经过测试,元素相同的也可以用哈希表判断出来的。

发布了32 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/C1033177205/article/details/104159723