代码随想录算法训练营Day6 —— 242.有效字母异位词、349.两个数组的交集、202.快乐数、1.两数之和

 242.有效字母异位词

思路:

一知半解,看了视频才通透,原来可以通过只需要将 s[i] - ‘a’ 所在的元素做+1 操作,本来不知道怎么和数组联系起来,数组索引做减法字符串直接算ASCII码,主要学会采用字符串的遍历方式

代码: 

自己看完解答手搓的代码,一看就会一写就废,通过求和的话只要字符串长度相同都会输出true,那还判断啥...

//傻逼了,用求和判定
class Solution {
public:
    bool isAnagram(string s, string t) {
        int hash[26] = {0};
        int sum = 0;
        for(int i = 0; i < s.size(); i++){
            hash[s[i]-'a']++;
        }
        for(int j = 0; j < t.size(); j++){
            hash[t[j]-'a']--;
        }
        for(int k = 0; k < 26; k++){
            sum += hash[k];
        }
        if (sum == 0) return true;
        return false;
    }
};

正解:

class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for (int i = 0; i < s.size(); i++) {
            // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
            record[s[i] - 'a']++;
        }
        for (int i = 0; i < t.size(); i++) {
            record[t[i] - 'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if (record[i] != 0) {
                // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        // record数组所有元素都为零0,说明字符串s和t是字母异位词
        return true;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

349.两个数组的交集

思路:

交集记得要去重,set就可以直接去重,数组的话需要判定新的数再添加。数组对比于set,如{0,5,1000}如果用数组的话会浪费很多空间,因为要定义一个array[1000]。

将nums1存在哈希表内,遍历每一个值,再再nums2中用哈希表查找。要注意返回的时候写法。

代码:

用set

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set;//用来存放最后结果,不需要去重
        unordered_set<int> num_set(nums1.begin(), nums1.end());//通过迭代器初始化集合元素范围
        for (int num : nums2){//遍历每个元素
            //利用哈希表查询
            if(num_set.find(num) != num_set.end())//当找不到时候会返回尾部迭代器,不等于意思是找到了
            result_set.insert(num);
        }
        //return result_set; 这样是错的,不能直接返回set
        return vector<int>(result_set.begin(), result_set.end());//返回开始到结尾位置的元素
    }
};
  • 时间复杂度: O(mn)
  • 空间复杂度: O(n)

直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。

用数组:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重
        int hash[1005] = {0}; // 默认数值为0
        for (int num : nums1) { // nums1中出现的字母在hash数组中做记录
            hash[num] = 1;
        }
        for (int num : nums2) { // nums2中出现话,result记录
            if (hash[num] == 1) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};
  • 时间复杂度: O(m + n)
  • 空间复杂度: O(n)

202.快乐数

思路:

其中查询是否出现过可以用哈希表,此外要注意判定,先判定是否出现1,再判定是否循环。

代码:

class Solution {
public:
    // 取数值各个位上的单数之和
    int getSum(int n) {
        int sum = 0;
        while (n) {
            sum += (n % 10) * (n % 10);
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> set;
        while(1) {
            int sum = getSum(n);
            if (sum == 1) {
                return true;
            }
            // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
            if (set.find(sum) != set.end()) {
                return false;
            } else {
                set.insert(sum);
            }
            n = sum;
        }
    }
};
  • 时间复杂度: O(logn)
  • 空间复杂度: O(logn)

1.两数之和

思路:

本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能

此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value再保存数值所在的下标。

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树,这道题目中并不需要key有序,选择std::unordered_map 效率更高! 

map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)

接下来是map中key和value分别表示什么。

这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。

所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

代码:

手搓:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        std::unordered_map <int,int> map;
        for (int i = 0; i < nums.size(); i++){
            int num = target - nums[i];
            if(map.find(num) != map.end()){
                return {map.find(num)->second, i};
            }
            map.insert(pair<int,int>(nums[i],i));
        }
        return {};
    }
};
//卡哥标准代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        std::unordered_map <int,int> map;
        for(int i = 0; i < nums.size(); i++) {
            // 遍历当前元素,并在map中寻找是否有匹配的key
            auto iter = map.find(target - nums[i]); 
            if(iter != map.end()) {
                return {iter->second, i};
            }
            // 如果没找到匹配对,就把访问过的元素和下标加入到map中
            map.insert(pair<int, int>(nums[i], i)); 
        }
        return {};
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值