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

文章讲述了如何在LeetCode题目中运用哈希表,如数组、HashSet和HashMap,解决有效字母异位词、两个数组交集和快乐数等问题,强调了哈希数据结构在解决这类问题时的优势和适用场景。
摘要由CSDN通过智能技术生成

LeetCode 242 有效字的字母异位词

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

作为哈希表系列的第一题,此题的目的是让我们明白:数组其实就是一个简单的哈希表

同时也让我们了解用数组做哈希映射时该怎么做

【解题思路】

大体思路:用一个数组记录两个字符串中每个字母出现的次数。

1.定义一个数组record用来记录字符串s里字符出现的次数,大小为26,初始化为0。

        之所以定义大小为26,初始化为0,是因为在ASCII码中,字符a到字符z也是26个连续的                数值,我们需要将字符a-z定义为数组的下标,在字符串中,每遍历到一个字符,代表其的下          标中的元素+1,这样我们就能统计出当前字符串每个单词的出现次数了。

2.将字符a到字符z映射到数组的索引下表上,字符a映射为下标0,字符z映射为下标25。
        具体做法是:在遍历字符串时,将每个遍历出来的字符减去字符‘a’(因为字符a为a-z的开            头,又因为组成单词的字母只有a-z26个,将每次遍历出来的字符减去字符a,其差就可以当          做数组的下标使用。)
3.遍历字符串s,当出现字符时,相应字符下标位置里的元素+1。

4.遍历字符串t,当出现字符时,相应字符下标位置里的元素-1。

5.检查数组里的元素,如果record数组里有不为0的元素,则说明字符串s和t一定是谁多了或者少了字符,返回false;反之,如果record数组里所有的元素都为0,说明字符串s和t是异位词,返回true。

【代码部分】

java:

public boolean isAnagram(String s, String t) {
		int [] record = new int[26];

		for(int i = 0; i < s.length(); i++){
			record[s.charAt(i) - 'a']++;
		}

		for(int i = 0; i < t.length(); i++){
			record[t.charAt(i) - 'a']--;
		}

		for(int count:record){
			if(count!= 0){
				return false;
			}
		}
		return true;
    }

LeetCode 349 两个数组的交集

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

此题主要要求我们学会使用一种哈希数据结构,该结构在java中为:HashSet,这个数据结构可以解决很多类似的问题。

注意:根据实例可以发现输出结果中的每个元素一定是唯一的,也就是说输出的结果是去重的,同时可以不考虑输出结果的顺序。

【解题思路】

在LeetCode没有更改本题的测试用例(更改之后规定测试用例最大不超过1000)时,此题的数值可以很大,并且可能数值之间的跨度非常大。在此前提下,用数组做该题就会造成空间的极大浪费。

当哈希值比较少、特别分散、跨度非常大的时候,使用数组会造成空间的极大浪费!

此时,应该使用另一种结构体:set。

在java中,关于set提供了两种可用的数据结构:

  • TreeSet
  • HashSet

TreeSet的底层实现是红黑树,HashSet的底层实现是哈希表,TreeSet是有序的,HashSet是无序的,两者中,HashSet的效率是比较高的,另外,此题并不需要对数据进行排序,因此选择HashSet。

【代码部分】

public int[] intersection(int[] nums1, int[] nums2) {
		if(nums1 == null || nums1.length ==0 || nums2 == null || nums2.length == 0){
			return new int[0];
		}
		Set<Integer> set1 = new HashSet<>();
		Set<Integer> set2 = new HashSet<>();
		//遍历数组1
		for(int i : nums1){
			set1.add(i);
		}
		//遍历数组2的过程中判断哈希表中是否存在元素
		for(int i : nums2){
			if(set1.contains(i)){
				set2.add(i);
			}
		}
		return set2.stream().mapToInt(x -> x).toArray();
    }

LeetCode 202 快乐数

题目链接:LeetCode202. 快乐数

【题目思路】

根据题意可知:可能会有无限循环,也就是说求和过程中sum可能会重复出现!

因此,我们的解题思路应该是判断sum是否重复出现,重复的话就return false,如果没有重复,那就一直找到sum为止。

当我们遇到要快速判断一个元素是否出现在集合里的时候,优先考虑哈希法!!!

【代码部分】

 public boolean isHappy(int n) {
        Set<Integer> record = new HashSet<>();
        while (n != 1 && !record.contains(n)) {
            record.add(n);
            n = getNextNumber(n);
        }
        return n == 1;
    }

    private int getNextNumber(int n) {
        int res = 0;
        while (n > 0) {
            int temp = n % 10;//将n的个位数取出来
             n = n / 10;//将取出来的那一位数从n里去除
            res += temp * temp;//将取出来的数进行平方之后累加起来
            //重复以上步骤,直到n内没有数可取(也就是n<=0)
           
        }
        return res;
    }

【疑难点】

注意求和的过程,如果对取数值各个位上的单数操作不熟悉的话,此题会做的比较艰难。

LeetCode 1  两数之和

题目链接:LeetCode1.两数之和

有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。

因为此题在了解哈希法之前并不算简单。

这道题应该是大部分人梦的开始。

此题的目的是让我们明白什么时候该用map做哈希映射,以及怎么用map做哈希映射。

【解题思路】

再强调一下什么时候使用哈希法:

当我们遇到要快速判断一个元素是否出现在集合里的时候,优先考虑哈希法!!!

此题我们不仅需要知道元素有没有被遍历过,还要知道这个元素对应的下标,需要存放两个值,而map正好有两个值:一个key,一个value。因此,本体使用map正合适。

用数组和set来做哈希法的局限:

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

在java中,map有三种类型:

  • TreeMap:底层使用红黑树实现;key不可重复,效率为O(logn)
  • HashMap:底层使用数组+链表+红黑树实现;key不可重复,效率为O(1)
  • IdentityHashMap:底层使用哈希表实现;key可重复,效率为O(logn)

在此题中,我们需要保证key不可以重复的前提下,选择更高效的数据结构,因此我们使用HashMap。

接下来我们需要考虑两点:

  • map用来做什么
  • map中key和value分别表示什么

map用来存放我们访问过的元素,因为遍历数组的时候,我们需要把遍历过的元素及其对应下标记录下来,这样我们才能找到与当前元素匹配的元素。

key表示元素,因为我们要保证元素的唯一性,因此key必须唯一。

因此,value自然用来存放与元素对应的下标。

在遍历数组的时候,只需要向map去查询是否有和目前遍历元素相匹配的数值即可

如果有,即表示配对成功,返回两个元素对应的下标。

如果没有,即表示整个数组里没有两个元素相加等于target的情况。

【代码部分】

java:

public int[] twoSum(int[] nums, int target) {
		int [] res = new int[2];//用来存放匹配到的两个元素下标
		if(nums == null || nums.length == 0){
			return res;
		}
		Map<Integer,Integer>map =new HashMap<>();
		for(int i = 0; i < nums.length ; i++){
			int temp = target - nums[i];
			if(map.containsKey(temp)){
				 res[1] = i;//获取当前元素下标
				 res[0] = map.get(temp);//获取与之匹配的元素在数组中的下标
				 break;
			}
			map.put(nums[i],i);//如果没有找到匹配对,则将访问过的元素存入key,下标存入value
		}
		return res;
    }

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值