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

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

第一题 242.有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

ψ(`∇´)ψ 我的思路

  • 这是我拿到题一开始的思路,两个字符串装到俩个map中,再进行比较
package hash;

import java.util.HashMap;
import java.util.Set;

class IsAnagram {
    public static boolean isAnagram(String s, String t) {
        char c;
        HashMap<Character, Integer> smap = new HashMap<>();
        int len = s.length();//字符串的长度
        for (int i = 0; i < len; i++) {
            c = s.charAt(i);//挨个取出s字符串中的每一个字符
            if(smap.containsKey(c)){//如果key中已有c
                smap.put(c,smap.get(c)+1);//把c中原来的值+1再赋给c
            } else {
                smap.put(c,1);//如果key中没有c,添加c并赋值1
            }
        }

        HashMap<Character, Integer> tmap = new HashMap<>();
        for (int i = 0; i < len; i++) {
            c = t.charAt(i);//挨个取出t字符串中的每一个字符
            if(tmap.containsKey(c)){//如果key中已有c
                tmap.put(c,tmap.get(c)+1);//把c中原来的值+1再赋给c
            } else {
                tmap.put(c,1);//如果key中没有c,添加c并赋值1
            }
        }
        if(smap==tmap){
            return true;
        }else {
            return false;
        }
    }

    public static void main(String[] args) {
        String s = "anagram";
        String t = "nagaram";
        System.out.println(isAnagram(s, t));
    }
}
  • 后来debug发现==判断的是两个map的地址

  • 改进后的思路:只用一个map,第一个字符串存,第二个字符串取

public static boolean isAnagram(String s, String t) {
        if(s.length()!=t.length()){
            return false;//长度都不等,你还比个什么呢,返回吧
        }
        char c;
        HashMap<Character, Integer> map = new HashMap<>();
        int len = s.length();//字符串的长度
        for (int i = 0; i < len; i++) {
            c = s.charAt(i);//挨个取出s字符串中的每一个字符
            if(map.containsKey(c)){//如果key中已有c
                map.put(c,map.get(c)+1);//把c中原来的值+1再赋给c
            } else {
                map.put(c,1);//如果key中没有c,添加c并赋值1
            }
        }

        for (int i = 0; i < len; i++) {
            c = t.charAt(i);//挨个取出t字符串中的每一个字符
            if(map.containsKey(c)){//如果key中已有c
                map.put(c,map.get(c)-1);//把c中原来的值-1再赋给c
                if (map.get(c)==0){
                    map.remove(c);//当c的值减到0的时候移除c
                }
            } else {
                return false;//如果key中没有c,直接返回false
            }
        }
        if(map.isEmpty()){
            return true;
        }else {
            return false;
        }
    }
  • 通过之后我在写博客的时候发现只要将第一种方法的==换成equal就也可以通过😅
  • 看了官方题解,是字符串转成char[]后排序比较,就😶



第二题349. 两个数组的交集

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

ψ(`∇´)ψ 我的思路

  • 先把两个数组存到set里保证他们不重复,把其中一个set转成数组,不然没法遍历,第一遍遍历数组确定交集元素的数量,这样才能创建数组,第二遍遍历数组把交集元素存到数组中
package hash;

import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class Intersection {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new TreeSet<>();
        for (int i = 0; i < nums1.length; i++) {
            set1.add(nums1[i]);//把数组中的元素装到set里,确保每个元素只出现一次
        }
        Object[] arr1 = set1.toArray();//

        Set<Integer> set2 = new HashSet<>();
        for (int i = 0; i < nums2.length; i++) {
            set2.add(nums2[i]);//把数组中的元素装到set里,确保每个元素只出现一次
        }
        int j = 0;
        for (int i = 0; i < arr1.length; i++) {
            if(set2.contains(arr1[i])){
               j++;//这次遍历是为了得到数组的长度
            }

        }
        int[] res = new int[j];
        j = 0;
        for (int i = 0; i < arr1.length; i++) {
            if(set2.contains(arr1[i])){
                res[j++] = (int) arr1[i];//交集元素存入数组
            }

        }
        return res;
    }
}
  • 下面是代码随想录中的解法
import java.util.HashSet;
import java.util.Set;

class Solution {
    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> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
        //将结果几何转为数组
        return resSet.stream().mapToInt(x -> x).toArray();
    }
}
  • 我觉得这个解法挺好,把一个数组转成set,留了一个用来遍历,交集元素存入新set,最后set转array,这算是对我的解法的改进



第三题202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

ψ(`∇´)ψ 我的思路

  • 这题复杂是复杂了点,但顺着思路写还行,我目前写的程序可以把快乐数判断出来,返回true,不是快乐数的会一直循环所以超时的就不是快乐数🤪
  • 我现在可以把任何一个整形判断出来是不是快乐数但是却没法通过leetcode😅,因为我找不到结束循环的条件
package hash;

public class IsHappy {

    public static boolean isHappy(int n) {
        int sum = 0;
        int[] ints = intToInts(n);
        while (sum!=1){
            for (int i = 0; i < ints.length; i++) {
                sum +=ints[i]*ints[i];
            }
            if(sum==1){
                return true;
            }
            ints = intToInts(sum);
            sum = 0;
        }
        return true;
    }

    private static int[] intToInts(int n){
        // 先写一个方法把整数拆成数组
        int i = 1;
        int x = n;
        while (x/10!=0){
            x = x/10;
            i++;//确定整数的位数
        }
        int[] ints = new int[i];
        for (int j = 0; j < i; j++) {
            ints[j] = n%10;
            n = n/10;
        }
        return ints;
    }
}
  • 我回去又把题目看了一遍,

题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

  • 这就好办了,我把每一次计算出的sum记录下来,存在set中,sum在set中重复的时间点就是我该跳出循环的位置。
package hash;

import java.util.HashSet;
import java.util.Set;

public class IsHappy {

    public static boolean isHappy(int n) {
        int sum = 0;
        Set<Integer> set = new HashSet<>();
        int[] ints = intToInts(n);
        while (sum!=1){
            for (int i = 0; i < ints.length; i++) {
                sum +=ints[i]*ints[i];
            }
            if(!set.contains(sum)){//如果set中没有出现过sum
                set.add(sum);//把sum都加入到set中
            } else {//如果set中已经有sum,说明已经开始循环
                return false;
            }
            if(sum==1){
                return true;
            }
            ints = intToInts(sum);
            sum = 0;
        }
        return true;
    }

    private static int[] intToInts(int n){
        // 先写一个方法把整数拆成数组
        int i = 1;
        int x = n;
        while (x/10!=0){
            x = x/10;
            i++;//确定整数的位数
        }
        int[] ints = new int[i];
        for (int j = 0; j < i; j++) {
            ints[j] = n%10;
            n = n/10;
        }
        return ints;
    }
}




第四题1. 两数之和

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

  • 这这这,这不就是梦开始的地方嘛,这就是我注册leetcode那天写的题,把当时的代码粘下
class Solution {
    public int[] twoSum(int[] nums, int target) {
         int[] result = new int[2];
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j < nums.length ; j++) {
                if((nums[i]+nums[j])==target){
                    result[0] = i;
                    result[1] = j;
                }
            }
        }
        return result;
    }
}
  • 就是暴力!!!

ψ(`∇´)ψ 我的思路

  • 其实我想半天也没有想到用哈希表做题的思路,然后我就看了代码随想录的思路,真的是妙蛙种子吃了妙脆角妙到家啦hhh
package hash;

import java.util.HashMap;
import java.util.Map;

public class TwoSum {
    public static int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; i++) {
            //将数组的元素作为key,数组下标作为value存入map
            if(map.containsKey(target-nums[i])){//如果map中已经加入了要寻找的值
                res[0] = map.get(target-nums[i]);
                res[1] = i;//当前值的下标
            }
            map.put(nums[i],i);
        }
        return res;
    }
}
  • 我有想过把数组装到哈希表中,但是思维固化还是想着要以下标为key,没想到下标是value




总结


  • 感觉哈希表是比链表简单的,可能也是因为今天的四题都是简单题

  • 没啥问题,期待明天的中等题

  • 真的一天中第二快乐的事就是刷题了

  • 蔫儿蔫儿的今天,真的晚上不能再喝咖啡了,身体睡着了,灵魂还清醒

posted @ 2022-09-26 12:57  nnn~  阅读(163)  评论(0编辑  收藏  举报