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

文章讲述了如何使用哈希表判断两个字符串是否为字母异位词,以及利用哈希表和集合数据结构解决两个数组的交集问题。同时介绍了快乐数的判断方法和寻找数组中和为目标值的两个数的高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

242.有效的字母异位词

一、题目详情

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • s 和 t 仅包含小写字母

进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

二、解题思路

        用哈希表做。这里用简单的数组就可以完成。利用小写字母的ASCII码将他们转换成数组下标对应的0-25,遍历字符串,遇到一个字母就转换成数组下标,让这个下标的值加一来计算遇到了多少次。如果输入字符串包含unicode字符可以用map来解决,出现的Unicode字符为key,出现一次key,key对应的value就加一。

三、解题代码

class Solution {
public:
    bool isAnagram(string s, string t) {
        if(s.length()!=t.length()){
            return false;
        }
        vector<int> scnt(26, 0);
        vector<int> tcnt(26, 0);
        for(int i = 0; i< s.length();i++){
            int sl = s[i] - 'a';
            int tl = t[i] - 'a';
            scnt[sl]++;
            tcnt[tl]++;
        }

        for(int i = 0; i<26; i++){
            if(scnt[i]!=tcnt[i]){
                return false;
            }
        }
        return true;
    }
};

349. 两个数组的交集

一、题目详情

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

提示:

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

二、解题思路

        由于看到了提示,所以我建立了一个visited数组,以下标来判断和标记已访问的数字。首先第一遍,访问数组访问nums1,nums1有的数字作为visited数组的下标指向的值变为true,标记了nums1有什么数字。第二遍用nums2去遍历,这时候nums2元素作为visited数组的下标对应的元素为true才能放入答案数组,因为visited为false的元素对应的下标数字没有出现在nums1数组里面。但这时候nums2自己也会出现一个元素重复的问题,解决这个问题的方法是当该元素已经出现并加入了ans数组时候,将该元素指着的visited元素改回false,下次再出现就不会被放进ans了,因为nums2元素作为visited数组的下标对应的元素为true才能放入答案数组

        一开始不想用set的方法,set的方法也是可以的,但set完后还要改回vector才能返回。set的方法也很简单,建立两个set,一个Set1放nums1的元素,放进去后nums1内部出现重复的元素只会放一个进去。然后就遍历nums2,看看num2的元素在不在Set1里,在的话放进存放答案的集合SetA里。这时候遍历nums2就不用考虑nums2内部元素重复的问题了,因为集合元素唯一。然后再把SetA的元素塞进数组输出就行。这个方法的好处一个是节约空间,因为上面那个解法无论数组有多少元素有多大元素都只能把visited数组开到最大,而set可以随用随插,第二个好处是不用考虑数组内重复元素的问题,set自己的机制就能避免。

        在这道题中两种解法的效率差不多,范围越大的话set更优。

三、解题代码

访问数组解法

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<bool>visited(1010,false);
        vector<int>ans;
        for(int i = 0; i<nums1.size(); i++){
            if(!visited[nums1[i]]){
                visited[nums1[i]]=true;
            }
        }
        for(int i = 0; i<nums2.size(); i++){
            if(visited[nums2[i]]){
                ans.push_back(nums2[i]);
                visited[nums2[i]]=false;
            }
        }
        return ans;
    }
};

集合解法

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> Set1, SetA;
        vector<int> ans;

        for(auto& num : nums1){
            Set1.insert(num);
        }

        for(auto& num : nums2){
            if(Set1.count(num)){
                SetA.insert(num);
            }
        }

        for(auto& a : SetA){
            ans.push_back(a);
        }
        return ans;
    }
};

202. 快乐数

一、题目详情

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

提示:

  • 1 <= n <= 231 - 1

二、解题思路

        又是拆数,这种拆东西的活还是python好用啊——!没关系,C++也能拆,就是烦了点。陷入死循环意味着已经作为加平方结果出现过的数字又出现了,出现第二次的运算结果会跟第一次一样一次次的绕回自己。那就是说要判断数字是否出现过,也就是用哈希表。

        这道题就用的set了,因为范围太大了。每次加完结果看看结果是不是1,是的话结束,不是的话看看在不在集合里,在的话死循环,不在的话加进去继续循环。


        这道题还可以用快慢指针解,因为如果有快乐数的话,结果接起来可以是一个无环链表,如果是死循环的话,那他就会是一个有环链表。快慢指针在这里的环形链表做过。

三、解题代码

class Solution {
public:
    int SquareSum(int n){
        int sum = 0;
        while(n>0){
            int temp = n%10;
            sum += temp*temp;
            n/=10;
        }
        return sum;
    }

    bool isHappy(int n) {
        unordered_set<int> sums;
        int sum = SquareSum(n);
        while(sum!=1){
            if(sums.count(sum)){
                return false;
            }
            sums.insert(sum);
            n = sum;
            sum = SquareSum(n);
        }
        return true;
    }
};

1. 两数之和

一、题目详情

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

二、解题思路

        现在看到这种题要是写到了O(n^2)都有种罪恶感……一开始没琢磨明白数组中同一个元素在答案里不能重复出现是怎么个事,想着要不用map,看了题解说unordered_map也行(也确实是用了这个),那就是说这个数组不会出现重复元素。

        第一遍循环,让map认认数组的元素和他们的下标。key用的是数组元素,value是对应下标,因为找到条件也是数组元素有关。

        第二遍循环,对于数组里的每一个数都在map里面找有没有跟这个数加起来等于target的,也就是要找target-当前数的元素,也就是说key=target-当前数。如果存在这个key,而且这个key对于的下标不是他自己(数组中同一个元素在答案里不能重复出现),那这个数和数字里除了它外的另一个数(target-当前数)就是我们要找的元素,返回他们的下标(key对应的value)就行。如果没有就返回空对。这样的复杂度是O(n)

三、解题代码

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> Map;
        for(int i = 0; i < nums.size(); i++){
            Map[nums[i]] = i;
        }
        for(int i = 0; i < nums.size(); i++){
            if(Map.count(target-nums[i])&&Map[target-nums[i]]!=i){
                return {i, Map[target-nums[i]]};
            }
        }
        return {};
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值