代码随想录算法训练营Day06 | LeetCode242.有效的字母异位词、LeetCode349.两个数组的交集、LeetCode202.快乐数、LeetCode1.两数之和

什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。 这句话很重要。

LeetCode242.有效的字母异位词

题目链接:https://leetcode.cn/problems/valid-anagram/

思路:定义一个数组叫做record用来记录字符串s里字符出现的次数。把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

在遍历字符串s的时候,**只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。**这样就将字符串s中字符出现的次数,统计出来了。

接下来在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

C++代码如下:

class Solution 
{
public:
    bool isAnagram(string s, string t) 
    {
        int record[26] = {0};
        for(int i = 0; i < s.size(); i++)
        {
            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)
            {
                return false;
            }
        }
        return true;
    }
};

LeetCode349.两个数组的交集

题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/

思路:看到该题的第一想法是:把nums1中的元素存在set类型的变量s1中,再在s1中找是否存在nums2中的元素,有的话存在一个vector类型变量result中,那么result里存放的就是nums1和nums2共同有的元素,即交集。

C++代码如下:

class Solution 
{
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) 
    {
        set<int> s1;
        vector<int> result;
        for(int i = 0; i < nums1.size(); i++)
        {
            s1.insert(nums1[i]);  //插入数据
        }
        for(int i = 0; i < nums2.size(); i++)
        {
            set<int>::iterator pos = s1.find(nums2[i]);  //定义一个迭代器来接收find()的返回值
            if(pos != s1.end())
            {
                result.push_back(*pos);
            }
        }
        //此时得到的result也算是正确的,但是还没去重,下面部分代码功能是去重。
        set<int> s2;
        vector<int> res1;
        for(int i = 0; i < result.size(); i++)
        {
            s2.insert(result[i]);
        }
        for(set<int>::iterator it = s2.begin(); it != s2.end(); it++)
        {
            res1.push_back(*it);
        }
        return res1;
    }
};

分析:总感觉自己写的有些太啰嗦了,看了卡哥写的,发现是自己的简洁版。我写的代码中,在查找s1中是否存在nums2里的元素时,是把查找结果存在vector类型的result变量中,后面又把result变量中的元素存在set类型的s2中,并且去重之后又把结果存在vector类型的res1变量中再输出。卡哥的做法是:在查找nums_set中是否存在nums2里的元素时,直接把结果存在unordered_set类型的变量result_set中,然后直接输出该变量,而我是先经过vector类型再存在set类型中,而且最后输出之前还是转成vector再输出,就显得很啰嗦冗余。

C++代码如下:

class Solution
{
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
    {
        unordered_set<int> result_set;    //存放结果
		unordered_set<int> nums_set(nums1.begin(), nums1.end()); //用nums容器中的元素为新建的nums_set容器初始化。
		for (int num : nums2)             
		{
			//发现nums2的元素 在nums_set里又出现过
			if (nums_set.find(num) != nums_set.end())    //说明在nums_set中找到num
			{
				result_set.insert(num);                  //将出现的数插入result_set中
			}
		}
		return vector<int>(result_set.begin(), result_set.end());    
    }
};

LeetCode202.快乐数

题目链接:https://leetcode.cn/problems/happy-number/

思路:看到这题的第一想法是:把输入的数由int转为string类型,再一位一位的平方相加,再判断是不是1,是的话返回true,否则继续一位一位平方相加;但是题目说了有可能无限循环,所以定义一个哈希表set或unordered_set将之前相加后的结果存进去,之后的每次数字平方和结果还要再在哈希表内查找一遍看是否存在,若存在就会陷入无限循环,直接return false。

思路其实蛮简单的,但是在测试过程中一直出错,后面经过debug找出原因,需要注意以下几点:

  1. 每次计算一个正整数的每个位置上数字的平方和,我是使用int型变量result来接收结果,再做后续的判断以及存储在哈希表中。但是在下一回合计算每个位置上数字的平方和之前,记得要把result归零、置位,否则它会把之前的结果累加进去,那就报错了。

  1. 输入的是int型变量,由于我打算计算该变量的每个位置上数字的平方和,所以我的做法是把int型变量转为string型,再分别计算string型变量上每一位置的数字的平方和,但是,我忘记一件事情,就是string变量上的每一位都是char型,而不是int型,即它们是char型的’1’而不是int型的’1’,所以我直接s1[i]*s1[i]就变成两个char型变量相乘,这就出错了!后来,我改成用char型变量接收s1[i],再用强制转换把char转为int,再计算两个int型相乘即可,如下图所示:

char tmp01 = s1[i];
int tmp = (int)tmp01 - 48; //因为ascii码的数字(0)从48开始
result += tmp * tmp;

同时要注意的是,ascii码的数字‘0’是从48开始,也就是说char tmp01 = ‘0’; int tmp = (int)tmp01其实是48,所以后面要减去48,为了让tmp从0开始。

C++代码如下:

class Solution {
public:
	bool isHappy(int n)
	{
		unordered_set<double> set1;
		set1.insert(n);
		string s1 = to_string(n);
		int result = 0;
		while (1)
		{ 
			result = 0;
			for (int i = 0; i < s1.size(); i++)
			{
				char tmp01 = s1[i];
				int tmp = (int)tmp01 - 48;  //因为ascii码的数字(0)从48开始
				result += tmp * tmp;
			}
			if (result == 1)
			{
				return true;
			}
			else
			{
				unordered_set<double>::iterator pos = set1.find(result);
				if (pos != set1.end())  //找到了
				{
					return false;
				}
				else
				{
					set1.insert(result);  //存在哈希表中
					s1 = to_string(result);
				}
			}
		}
	}
};

分析:后来再想,原思路虽然是正确的,但是int型和char型转来转去太麻烦了,容易出错,后面参考卡哥的写法,对输入int型参数使用 % 与 / ,就可以得到该int型变量的个位、十位、百位等等,还不容易出错。

C++代码如下:

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;
        }
    }
};

LeetCode1.两数之和

题目链接:https://leetcode.cn/problems/two-sum/

思路:想法是使用哈希表,使用unorderewd_map,一开始我的想法是key存放下标,value存放元素,但是使用find()函数的话,该函数是查找key是否存在,可是我需要得到的结果就是下标,所以后来改成key存放元素,value存放下标,通过查找需要的元素来返回对应的下标。

C++代码如下:

class Solution 
{
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        vector<int> result;
        unordered_map<int, int> mp1;
        for(int i = 0; i < nums.size(); i++)
        {
            unordered_map<int, int>::iterator pos = mp1.find(target-nums[i]);
            if(pos != mp1.end())   //找到了
            {
                result.push_back(i);
                result.push_back((*pos).second);
                return result;
            }
            else
            {
                mp1.insert(pair<int, int>(nums[i], i));
            }
        }
        return {};
    }
};

总结:整体上比链表容易,但是与set和map相关的语法函数再看看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值