算法—(3)哈希表

该节运用到很多c++特有的语法,后面会专门发一个涉及到的c++讲解。

一、前言:首先介绍一下哈希表,哈希表是通过关键值直接访问数据结构,关键值是通过哈希函数根据内容映射到关键值上,如果映射到同一个关键值上就需要另一个关键的哈希冲突,这里不细讲。

      在使用哈希法解决问题时候一般会采用如下三种数据结构:

      1.数组

      2.set(集合)

         set可以看作是我们数学中学到的集合,所记录的值也只有1个,所以一般判断是否存在这种问题上采用set比较合适。

      3.map(映射)

        map可以看作一个一个的键值对(<key,value>),通过关键值key来找到value。map一般用于比较复杂的判断。

二、有效的字母异位词

   1.题目描述:判断2个字符串是否可以通过调换顺序使其相同。

   2.思路分析:可以很清晰的知道出现的字符是固定的26个英文字母,这样他们的关键值就已经确定,可以通过一个数组来记录其出现过的次数,只要另一个字符串将这些清零就符合要求。

   3.注意事项:提升效率的方法:通过判断字符个数是否相同可以直接判断,如果相同的话后面只要每一个字符都满足,不需要重新判断是否清零也可以判断。

三、俩个数组的交集

   1.题目描述:求2个数组的交集,不能有重复的数据。

   2.思路分析:求2个数组的交集而且不能有重复的数据,这个只需要记录交集的数据就行了,通过查找数据得出交集的数据即可,也就是说只需要一个数据,这时候我们想到的就是set集合,又因为不用考虑顺序和不能重复,采用unordered_set。

   3.注意事项:这里需要注意unordered_set的函数应用。

                       unordered_set<int> nums_set(nums1.begin(),nums1.end())

                        //将nums1转换成unordered_set降重,nums1.begin(),nums1.end()为迭代器。

                       nums_set.find(num)

                       //在set中查找num值,如果存在则返回指向该值的迭代器,否则返回end()迭代器

四、俩数之和

   1.题目描述:在数组中找到俩个数值之和等于target,返回这2个数值的下标。

   2.思路分析:很明显可知需要放回的是数值的下标,同时也需要通过数值来查找,所以需要记录的是2个数据,这里使用set就不太合适,这时候应该使用map。

           unordered_map<int, int> map;

           auto iter = map.find(target - nums[i])

           //auto定义一个迭代器,看是否能找到另外一个符合要求的加数。

           if(iter != map.end())result {iter ->second,i}

          \\iter->second找的是<key,value>的value。

           else map.insert(pait<int ,int>(nums[i],i))

           //没找到将数据传入map中。

五、四数相加(数据独立且可以重复)

 1.题目描述:四个独立的数组,每个数组找一个相加等于0,共有多少种。

 2.思路描述:通过遍历2个数组,将每种和的组合统计次数,通过map储存起来,再遍历另外2个数组,通过四、俩数之和的思路可以得出答案。

3.注意:不需要考虑重复的情况。

六、三数相加(数据不独立且不能重复)

1.题目描述:在一个数组中,寻找加起来等于0的组合,不能重复。

2.思路描述:可能会考虑上面的2种方法,通过向确定2个数通过哈希表来找另外一个数,但是这里有个核心问题就是不能重复,当然也可以找出答案后去重,但是这样太复杂了。

因此这里最好采用双指针法。首先排序,再通过一个循环来定死一个数,再通过2个指针来指向另外2个数,进行判断。

class Solution {

public:

    vector<vector<int>> threeSum(vector<int>& nums) {

        vector<vector<int>> result;

        sort(nums.begin(),nums.end());//进行排序

      for(int i = 0 ;i < nums.size(); i++){

          if(nums[i] > 0)return result;//进行剪枝,提前结束循环。

          if( i>0 && nums[i] == nums[i-1])continue;//每次都与前一个对比,达到去重效果

          int left = i + 1;

          int right = nums.size()-1;

          while(left < right){

              if(nums[left] + nums [right] + nums[i] > 0)right--;

              else if(nums[left] + nums [right] + nums[i] < 0)left++;

              else {result.push_back(vector<int> {nums[i],nums[left],nums[right]});

               while( left < right && nums[left] == nums[left+1] )left++;

              while(left < right && nums[right] == nums[right-1])right--;

                //这也是left和right的去重语句,这个语句一定要当找到一个符合的组才能去重,不然会丢失【0,0,0】这种情况。因为left和right去重语句是通过与下一个数据进行比较的,如果直接进行比较,会造成符合条件的情况丢失。

              left++;right--;}

          }

      }return result;

    }

};

七、四数之和

1.题目描述:与六相同,只是数据变成四个,0变成另一target。

2.思路描述:与六相同,只是多加一层循环,但是要注意剪枝已经不再适用,因为target不再是0;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值