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

不同数据结构容器的分类

代码随想录算法训练营第6天|242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和_第1张图片

代码随想录算法训练营第6天|242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和_第2张图片

注:key值和value是不同的,key指下标索引,value是该索引存在的值

两个表格应该熟知,对不同的情况用不同的容器可以使时间和空间复杂度得到最优

242.有效字母的异位词

优解:思路:首先构建一个哈希表,即长度26的数组record,该数组的作用记录字母出现次数,下标0为a,1为b,以此类推下标25为z.然后先遍历串s,把出现过的字母对应下标+1(记录串s字母出现的次数);再遍历串t,相应出现的字母减1.最后把record数组从头遍历一遍,若全为0,则证明串s和串t的字母出现的次数都刚刚好,若有任何一个不为0,则说明串s或串t有多的或少的字母。

通过s[i]-'a'用下标进行映射,两者相减刚好是对应record数组下标对应字母。

代码:

bool isAnagram(string s, string t) {
        int record[26] = {0};
        for(int i = 0;i < s.size();i++){//统计串s字母出现次数
            record[s[i] - 'a']++;
        }
        for(int i = 0;i < t.size();i++){//串t出现的字母相应的减去
            record[t[i] - 'a']--;
        }
        for(int i = 0;i < 26;i++){//判断两串出现字母的次数是否相等
            if(record[i] != 0)
                return false;
        }
        return true;
    }

349.两个数组的交集

本题可用数组或集合实现,若元素少且最大的元素值大则考虑用集合。集合的优点是自动去除重复元素,方法多,且时间复杂度低。

思路:用低层容器为哈希表的set实现,先把nums1转换为集合,再遍历nums2和nums1的集合想比较,相同的元素存储到结果集合中,最后再把结果集合转换为数组返回。

tip:set.find()的定义

从set容器中查找值为x的元素

若存在,返回一个迭代器指向x,若不存在,返回一个迭代器指向set.end()

代码:

vector intersection(vector& nums1, vector& nums2) {
        unordered_set result_set;//存放两集合相同的元素
        unordered_set nums_set(nums1.begin(),nums1.end());//把nums1转换为set
        for(int nums:nums2){
            if(nums_set.find(nums) != nums_set.end()){
                result_set.insert(nums);
            }//若相等则存储该元素
        }
        return vector(result_set.begin(),result_set.end());
    }

202.快乐数

题意:例如1,拆开为1和9,分别平方相加等于82,再把82拆开成8和2,平方相加,以此类推。和为1既快乐数。

思路:例如19两位数,两位数每个位置最大都为9,则2位数的平方求和为9^2+9^2=162,若在平方求和途中出现重复的数,则证明此时已经出现了环,若没出现和为1,则以后肯定也不会再出现,因为此时已经在环内无限循环。

可以用142题的双指针法来判断环的出现,也可用集合的方法。

代码:以下为集合的方法,可以快速判断是否有出现重复的元素

int getsum(int n){//各位置的平方求和
        int sum = 0;
        while(n){
            sum += (n % 10) * (n % 10);
            n/=10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set set;
        while(1){
            int sum = getsum(n);
            if(sum == 1){//和为1为快乐数
                return true;
            }
            if(set.find(sum) != set.end()){//该和在集合中出现过,则出现了环
                return false;
            }
            else{
                set.insert(sum);
            }
            n = sum;
        }
    }

1.两数之和

思路:若目标值20,当前数组值为2的时候,可以往前查找是否有值为18的元素,若有返回两数的下标,没有则继续往后遍历到数组结束。

解1(暴力解):利用两个for循环,外层循环从数组头遍历到数组尾,外层遍历到一个值时,内层for就往前找是否有相符的差值,若有返回两者下标,没有则继续遍历结束。

解2(map):因为需要查找值且要知道该值的数组下标,并且还需查集合是否有出现过的元素,此时可以用map。从头遍历数组,每次都在map中查询该下标值与目标值的差值在集合中是否出现过,若出现过则返回当前遍历的下标和在集合中查找的下标,若没有则继续把该遍历值和下标存储在map中,循环到结束。

vector twoSum(vector& nums, int target) {
       std::unordered_map  map;
        for(int i = 0;i < nums.size();i++){
            auto iter = map.find(target - nums[i]);//把数组与目标值相差的值存储到迭代器
            if(iter != map.end()){//该差值元素存在于集合中,返回两个元素的下标
                return {iter->second,i};
            }
            map.insert(pair (nums[i],i));//没找到之前有符合的值,则把当前的键值对存储到map中
        }
        return {};//没有符合的数,返回空
    }

你可能感兴趣的:(算法,数据结构)