day06 有效的字母异位词 两个数组的交集 快乐数 两数之和

题目1:242 有效的字母异位词

题目链接:242 有效的字母异位词

题意

判断字符串t是否是字符串s的字母异位词  (字母异位词:s和t中每个字符串出现母次数都相同,且仅包含小写字符) 

数组

a~z是连续的  所以可以映射到数组的下标即  a->0  b->1......z->25  所以定义hash数组为hash[26]

先遍历第一个字符串每个字母出现的频率,再遍历第二个字符串,在第一个计算频率的基础上,减去第二个字符串相应的字母出现的频率

最终的hash数组中每个下标处的元素值均为0,那么说明两个字符串互为异位词,否则,不是异位词

代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        int hash[26] = {0};  //初始化为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 i=0;i<26;i++){
            if(hash[i]!=0){
                return false;
            }
        }
        return true;  
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1),因为定义的是一个常量大小的辅助数组

题目2: 349 两个数组的交集

题目链接:349 两个数组的交集

题意

求数组nums1 和 nums2的交集  输出结果中的元素不重复,不考虑顺序

1<=nums1.length,nums.length<=1000     0<=nums1[i],nums2[i]<=1000

数组

将nums1数组放置到哈希表(数组)中,然后再遍历第二个数组nums2,判断nums2中的元素是否在nums1中出现过,若出现过,就放到result数组中

最终的结果使用unordered_set保存,可以去重

代码

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result; //使用unordered_set数据结构可以去重
        int hash[1001] = {0};
        for(int i=0;i<nums1.size();i++){
            hash[nums1[i]] = 1; //将nums1中的元素存放到哈希表hash数组中
        }
        for(int i=0;i<nums2.size();i++){
            if(hash[nums2[i]]==1){
                result.insert(nums2[i]); //遍历nums2数组,在nums1的hash表中进行查找
            }
        }
        return vector<int>(result.begin(),result.end());
    }
};
  • 时间复杂度: O(m + n)
  • 空间复杂度: O(n)

set

将nums1数组中的元素放置到哈希表(unordered_set)中,然后遍历nums2数组 ,看在nums2中是否可以找到元素和存放在哈希表(unordered_set)的元素一致,如果找到,就放入到result,result也是unordered_set结构,可以去重

代码

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result; //使用unordered_set数据结构可以去重
        unordered_set<int> nums_set(nums1.begin(),nums1.end()); //将nums1放入到哈希表set中,可以去重
        //遍历nums2数组,看在nums2中是否可以找到元素与nums1中元素相等
        for(int i=0;i<nums2.size();i++){
            if(nums_set.find(nums2[i])!=nums_set.end()){
                result.insert(nums2[i]); //遍历nums2数组,在nums1的hash表中进行查找
            }
        }
        return vector<int>(result.begin(),result.end());
    }
};

  • 时间复杂度: O(n + m) m 是最后要把 set转成vector
  • 空间复杂度: O(n)

题目3:202 快乐数

题目链接:202 快乐数

题意

判断n是否为快乐数

快乐数:正整数n 替换为各个位的平方和sum,一直重复这个求和替换的过程直到数字变为1,如果可以变为1,则n是快乐数;sum也可能无限循环,变不到1,则不是快乐数

关键:无限循环,sum一定会重复出现,使用哈希表

原因:n的取值范围是[1,2^31-1],2^31-1=2147483647,一共10位,这10位中每一位最大取值是9,所以平方和最大是9^2*10=810,因为2147483647<999999999,所以重复的过程中,各个位的平方和小于810,无论重复多少次,各个位的平方和的取值是有限的,一定在[1,810]之间,是有限值。

所以,这说明非快乐数的n,对应的sum会重复出现,因此,可以使用哈希表判断一个元素是否重复出现在集合里

如果无限循环,说明sum会重复出现,则不是快乐数,如果没有重复,则是快乐数

数组

代码

class Solution {
public:
    int getsum(int n){
        int sum = 0;
        while(n){
            sum += (n%10) * (n%10);
            n = n/10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int hash[810] = {0};
        while(1){
            int sum = getsum(n);
            if(sum==1){
                return true;
            }
            if(hash[sum]==1){
                return false;
            }//如果sum下标在hash数组中的元素为1,说明这个sum在hash中已经出现过
            //不能先赋值再查找,因为已经赋值了,再查找的话,肯定能找见
            hash[sum] = 1;
            n = sum;//记得最终更新n,继续下一次循环
        }
    }
};

set

本题的元素数值较大且还需要判断元素是否重复出现,因此使用unordered_set

代码

class Solution {
public:
    int getsum(int n){
        int sum = 0;
        while(n){
            sum += (n%10) * (n%10);
            n = n/10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> sum_set;
        while(1){
            int sum = getsum(n);
            if(sum==1){
                return true;
            }
            if(sum_set.find(sum)!=sum_set.end()){
                return false;
            }//这里一定要先找sum,如果找到了直接false
            //不能先插入再查找,因为已经插入了,再查找的话,肯定能找见
            sum_set.insert(sum);
            n = sum;//记得最终更新n,继续下一次循环
        }
    }
};
  • 时间复杂度: O(logn)
  • 空间复杂度: O(logn)

题目4:1 两数之和

题目链接:1 两数之和

题意

找出nums数组中和为target的两个整数,返回对应的下标,数组中的元素不能重复使用

每种输入只会对应一个答案,这一点很重要

以上的这个数组就不满足要求,因为这个数组中有3个对应的答案,所以不满足要求

暴力解法

因为题目的数值较大且数值较为分散,所以首先想到了使用set解决

set
步骤

① 循环遍历数组的元素,求解target-nums[i],将差值存放在哈希表中

由于unordered_set可以去重并且增删查的效率很高,因此哈希表使用unordered_set

② 遍历该元素之后的各个元素,查看数组中是否有元素和差值相等,即判断数组的元素是否在set中出现过,如果存在,就将下标记录下来,紧接着,一定要记着删除放在det中的差值,因为我们始终要找的是当前的差值和数组中该元素之后的元素是否相等,如果set中一直保留以前的差值,可能会对结果产生干扰

下面的案例就是开始报错的案例,就是因为一直保留set中的值,所以出现了错误,不同组的元素查找同一个diff,图左就是一个典型,解决的方法就是把已经匹配到的diff元素从set中删除,这样相同的元素(3+3=6,4+4=8......)就不会重复查找到了

伪代码

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_set<int> diff_set;//定义一个set存放差值
        vector<int>index;//存放最终的下标
        for(int i=0;i<nums.size();i++){  //这里写nums.size()-1也可,因为最后一个元素,判不判定都无所谓,后面没有与之匹配的元素了
            int diff = target - nums[i];  //差值
            diff_set.insert(diff);   //将差值放入到set
            for(int j=i+1;j<nums.size();j++){   //遍历当前元素之后的元素
                if(diff_set.find(nums[j])!=diff_set.end()){//在之后的元素找到了等于差值的元素
                    index.push_back(i);//存放下标
                    index.push_back(j);
                    diff_set.erase(diff);//!!!因为会有重复数字的过程 如果不删除的话就会错误查找,这一步很重要,diff改为nums[j]也可,两者相等       
                    break;
                }
            }
        }  
        return index; 
    }
};
  • 时间复杂度: O(n^3),两层for循环 ,erase的操作时是O(n)
  • 空间复杂度: O(n)
数组

基于以上set的方法的原理,想到可以用到数组,将diff差值直接放到数组中。

这个解法和直接暴力解法相同,只是将数值放到了大小为1的数组中,其实这样并没有意义,但是因为这节学了哈希表,先想到了把差值diff放到数组中,后来才想到直接暴力的想法,学的还是有点死了

代码1(使用vector容器)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> diff_result;//定义一个数组存放差值
        vector<int>index;//存放最终的下标
        for(int i=0;i<nums.size();i++){  //这里写nums.size()-1也可,因为最后一个元素,判不判定都无所谓,后面没有与之匹配的元素了
            int diff = target - nums[i];  //差值
            diff_result.push_back(diff);   //将差值放入到数组中
            for(int j=i+1;j<nums.size();j++){   //遍历当前元素之后的元素
                if(nums[j]==diff_result[0]){//在之后的元素找到了等于差值的元素
                    index.push_back(i);//存放下标
                    index.push_back(j);
                    break;
                }
            }
            diff_result.pop_back();//!!因为会有重复数字的过程 如果不删除的话就会错误查找,这一步很重要
        }  
        return index; 
    }
};
  • 时间复杂度: O(n^2),两层for循环
  • 空间复杂度: O(n)

代码2(基于上述的vector容器,想到也可以使用int型数组hash[0],只包含一个元素)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int hash[1];//定义一个数组存放差值
        vector<int>index;//存放最终的下标
        for(int i=0;i<nums.size();i++){  //这里写nums.size()-1也可,因为最后一个元素,判不判定都无所谓,后面没有与之匹配的元素了
            int diff = target - nums[i];  //差值
            hash[0] = diff;   //将差值放入到数组中
            for(int j=i+1;j<nums.size();j++){   //遍历当前元素之后的元素
                if(nums[j]==hash[0]){//在之后的元素找到了等于差值的元素
                    index.push_back(i);//存放下标
                    index.push_back(j);
                    break;
                }
            }
        }  
        return index; 
    }
};
  • 时间复杂度: O(n^2),两层for循环
  • 空间复杂度: O(n)
直接

基于以上的hash数组中,只包含1个元素,想到使用直接暴力方法,绕了一个大弯😂

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int>index;//存放最终的下标
        for(int i=0;i<nums.size();i++){  //这里写nums.size()-1也可,因为最后一个元素,判不判定都无所谓,后面没有与之匹配的元素了
            int diff = target - nums[i];  //差值
            for(int j=i+1;j<nums.size();j++){   //遍历当前元素之后的元素
                if(nums[j]==diff){//在之后的元素找到了等于差值的元素
                    index.push_back(i);//存放下标
                    index.push_back(j);
                    break;
                }
            }
        }  
        return index; 
    }
};
  • 时间复杂度: O(n^2),两层for循环
  • 空间复杂度: O(n)

map

既要知道元素是否在数组中出现过,还要知道下标,因此使用key-value结构较合适,map比较合适 ,key存放元素,根据key就可查询这个元素是否出现过;value存放下标,如果key出现过,那么返回对应的value

!!!map存放的是遍历过的元素!!!这一点很重要

使用unordered_map,读写的效率很高

这个思路和暴力解法的思路不一样,暴力解法找的是该元素之后的元素,而map存放的是已经遍历的元素,查询的是之前已经遍历的元素。

遍历元素时,查询map中是否有与当前元素(diff)相匹配的元素,如果有,则直接return;没有的话,就将当前元素nums[i]及其下标i放到map中。

代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> map;//存放遍历过的元素 key value
        for(int i=0;i<nums.size();i++){
            int diff = target - nums[i];//差值
            auto inter = map.find(diff);//在map中寻找是否出现过与该元素nums[i]对应的差值(key)
            //inter含有key value两个元素
            if(inter!=map.end()){//在map中找到了元素nums[i]对应的差值(key),所以找到了一组元素(key value)
                return {inter->second,i};
                break;//因为只有1组满足
            }
            // else{
            //     map.insert(pair<int,int>(nums[i],i));
            // }
            map.insert(pair<int,int>(nums[i],i));//这段代码放到else里面也可以,还是因为只有1对,因为if里面已经return了,所以else和不else均可,所以可以这样操作
        }
        return {};
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)
  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以先将年月日拼接成一个字符串,然后使用 Set 数据结构进行去重。 假设有两个数组 arr1 和 arr2,其中每个元素包含年(year)、月(month)、日(day)三个属性,可以按照如下方式进行去重: ```javascript const newArr = [...arr1, ...arr2].map(item => item.year + '-' + item.month + '-' + item.day) const uniqueArr = [...new Set(newArr)] ``` 上述代码中,首先将两个数组合并为一个新数组,然后使用 `map` 方法将每个元素拼接成一个字符串。最后,使用 `Set` 去重并将其转换为数组类型即可得到去重后的结果。 ### 回答2: 在前端中实现两个数组中的年月日去重可以通过以下步骤完成。 1. 首先创建一个新数组用于存储去重后的年月日据。 2. 将两个数组合并为一个数组。 3. 遍历合并后的数组。 4. 在遍历过程中,使用一个对象来记录已经出现过的年月日据,并以年月日作为属性进行标记。 5. 检查当前年月日是否在对象中存在,若不存在,则表示该年月日是唯一的,将其添加到新数组中,并在对象中进行标记。 6. 最后得到的新数组即为去重后的年月日据。 以下是一种实现方式的示例代码: ```javascript function deduplicateDates(arr1, arr2) { let combinedArray = [...arr1, ...arr2]; let uniqueDates = []; let dateRecord = {}; combinedArray.forEach((date) => { let yearMonthDay = date.split('-').slice(0, 3).join('-'); // 假设日期格式为YYYY-MM-DD if (!dateRecord[yearMonthDay]) { uniqueDates.push(date); dateRecord[yearMonthDay] = true; } }); return uniqueDates; } let arr1 = ['2021-01-01', '2021-02-03', '2021-03-05']; let arr2 = ['2021-01-03', '2021-02-03', '2021-04-01']; let result = deduplicateDates(arr1, arr2); console.log(result); // ['2021-01-01', '2021-02-03', '2021-03-05', '2021-01-03', '2021-04-01'] ``` 以上示例代码中,通过遍历合并后的数组,并使用一个对象 `dateRecord` 记录已经出现过的日期据,实现了两个数组中的年月日去重的功能。 ### 回答3: 要实现两个数组中的年月日去重,可以采取以下步骤: 1. 将两个数组合并成一个新的数组,可以使用数组的concat()方法实现,例如:newArray = array1.concat(array2)。 2. 创建一个空的对象,用于存储去重后的年月日信息,例如:var uniqueDates = {}。 3. 遍历新数组中的每个元素,可以使用数组的forEach()方法实现。 4. 对于每个元素,提取其中的年月日信息,可以使用日期对象的getFullYear()、getMonth()和getDate()方法。 5. 将提取出的年月日信息拼接成一个字符串作为键,判断该键是否已经存在于uniqueDates对象中。如果不存在,则将该键添加到uniqueDates对象,并将对应的值设置为true,表示已经出现过。如果存在,则说明该年月日已经被记录过,无需重复记录。 6. 完成遍历后,uniqueDates对象中存储的键就是去重后的年月日信息。可以使用Object.keys()方法将键提取成一个数组。 7. 根据需求,可以将得到的数组进行排序、格式化等操作。 8. 最后得到的数组就是两个数组中去重后的年月日信息。 需要注意的是,此方法适用于两个数组的年月日去重,如果是多个数组,可以采取类似的思路进行处理。并且,如果数组中的元素不是日期类型,需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值