java哈希表实例

1 哈希表理论

哈希表其实就是存储的数据都带有索引的表格,常见的哈希表有数组、集合以及映射。哈希表最常见的问题叫作哈希碰撞,实际上就是同一个索引对应了多个值。
【哈希表一般用来快速判断一个元素是否在集合里】
解决哈希碰撞的方法有拉链法:将碰撞的数据存储在一个链表中
在这里插入图片描述
线性探测法:从哈希表上找一个空位来存储碰撞的数据,前提是哈希表的大小要大于数据所需要存储的数据数目的大小。
在这里插入图片描述

2 有效的字母异或位

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

        for (int i = 0; i< s.length(); i ++) {
            hashRecord[s.charAt(i) - 'a'] ++;               //ASCII码转字符  将对应哈希表位置索引加1
        }

        for (int i = 0; i < t.length(); i ++) {             //将对应哈希表位置索引减1
            hashRecord[t.charAt(i) - 'a'] --;
        }

        for (int count : hashRecord) {             //遍历哈希表
            if (count != 0) {
                return false;
            }
        }
        return true;
    }
}

3. 赎金信 (判断一个字符串是不是可以由另一个字符串的某些字符组成)

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] hashRecord = new int[26]; 

        for (char c : magazine.toCharArray()) {            //哈希表记录magazine中的字母索引   转换为字符数组
            hashRecord[c - 'a'] ++;
        }

        for (char c : ransomNote.toCharArray()) {
            hashRecord[c - 'a'] --;
        }

        for (int record : hashRecord) {               //如果不能构成的话会出现-1的情况
            if (record < 0) {
                return false;
            }
        }
        return true;
    }
}

4. 两个数组的交集

如果用数组来做哈希表的话,很可能会浪费空间。这里求交集要求输出是不重复的,因此使用集合做哈希表能够很好解决这个问题。
哈希表转换为数组的函数为:reSet.stream().mapToInt(x->x).toArray();

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> reSet = new HashSet<>();       //存放交集

        //遍历第一个数组并放入集合1中
        for (int num : nums1) {
            set1.add(num);  
        }

        //遍历第二个数组,判断其中的元素是否包含在第一个集合中
        for ( int num : nums2) {
            if (set1.contains(num) ) {   //包含
                reSet.add(num);
            }
        }

        //第一种方法:接下来将reSet集合转换为数组
       // return reSet.stream().mapToInt(x -> x).toArray();             //映射为数组,映射规则为x->x

        //第二种方法:另外申请一个数组存放reSet中的元素,并返回数组
        int[] arr = new int[reSet.size()];
        int i = 0;
         for (int re : reSet) {
            arr[i] = re;
            i ++;
         }
         return arr;
    }
}

5. 快乐数:一个正整数,将它的每一位平方和,再将结果不断平方和,最终结果为1的话就是快乐数,否则不是。用set

在这里插入图片描述

class Solution {
    public boolean isHappy(int n) {

        Set<Integer> record = new HashSet<>();      //构造一个哈希表
        while ( n != 1 && !record.contains(n)) {   //如果哈希表中不存在这个和就添加到哈希表中,直到这个数为1就截止
            record.add(n);
            n = getSum(n); 
        }
        return n == 1;
    }

        private int getSum(int n) {
            int temp = 0;
            int sum = 0;

            while (n > 0) {
                temp = n % 10;     //个位
                n = n / 10;        //个位之前的所有数
                sum += temp * temp;    //计算平方和
            }
            return sum;
        }
}

6. 两数之和:寻找数组中两个数的和为target的数组索引 用map

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];    //用于存放返回的数组下标

        if (nums == null || nums.length == 0) {
            return nums;
        }

        Map<Integer, Integer> map = new HashMap<>();           //构造一个map哈希表
        //遍历数组,从哈希表中找是否与数组的某一个元素和为target的元素
        for (int i = 0; i < nums.length; i ++) {
            int curNum = target - nums[i];
            //如果哈希表中的key与当前值相等
            if (map.containsKey(curNum)) {
                res[0] = map.get(curNum);             //获得value值
                res[1] = i;
                break;
            }
            map.put(nums[i],i);       //找不到匹配的就将当前的数组值和索引放入map中
        }
    return res;
    }
}

7. 四数相加:map

实例描述:给定四个包含整数的数组列表 A , B , C , D 。计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0
在这里插入图片描述在这里插入图片描述

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map = new HashMap<>();  
        int count = 0;      //记录元组的个数

        //遍历前两个数组,将它们的和与和出现的次数放到map里面
        for (int i : nums1) {
            for (int j : nums2) {
                int temp = i + j;
                if (map.containsKey(temp)) {
                    map.put(temp, map.get(temp) + 1);       //如果map里面有包含这个数,就将这个数出现的次数加1
                }
                else{
                    map.put(temp, 1);                       //没有的话次数就确定为1
                }
                
            }
        }

        //遍历后面两个数组 用0减去这两个数的和  如果在map中能找到相等的就提取map中两个和出现的次数
        for (int i : nums3) {
            for (int j : nums4) {
                int temp = 0 - i - j;
                if (map.containsKey(temp)) {                //如果存在相等的    
                    count += map.get(temp);
                }
            }
        }
    return count;
    }
}

8. 三数之和:双指针法

从一个数组中找出和为0的所有三元组集合

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();                            //存储三元组

        Arrays.sort(nums);                           //先排序

        for (int i = 0; i < nums.length; i ++) {
            if (nums[i] > 0) {                           //如果当前元素已经大于0,就没有必要继续往后了
                return list;
            }

            if (i > 0 && nums[i] == nums[i - 1]) {               //如果a有重复的话就跳过本次循环,从下一个a开始继续
                continue;
            }

            int left = i + 1;
            int right = nums.length - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum < 0) {
                    left ++;
                }
                else if (sum > 0){
                    right --;
                }
                else{
                    list.add( Arrays.asList(nums[i], nums[left], nums[right]));        //相等的时候

                    while (right > left && nums[left] == nums[left + 1]) left ++;           //对b去重
                    while (right > left && nums[right] == nums[right - 1]) right --;        //对c去重

                    right --;
                    left ++;
                }
            }
        }
        return list;
    }
}

9. 四数之和:双指针法

找出数组中和为target的四个元素
【涉及到去重的话双指针会更好处理一点】

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();

        Arrays.sort(nums);                                         //先从小到大排序

        for (int i = 0; i < nums.length; i ++) {
            
            /*如果mums[i] < 0 的话,尽管nums[i] > target
            那么其后的四个数加起来仍然有可能小于target
            */
            if (nums[i] > 0 && nums[i] > target) {                   //当前已经大于target了,就从下一个元素开始
                return list;
            }
            //a元素去重
            if ( i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            //三数之和
            for (int j = i + 1; j < nums.length; j ++) {
                //b元素去重
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }

                int left = j + 1;
                int right = nums.length - 1;
                while (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum < target) {
                        left ++;
                    }
                    else if(sum > target) {
                        right --;
                    }
                    else{
                        list.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));           //相等就加入到list列表中

                        //对c,d去重
                        while (right > left && nums[left] == nums[left + 1]) left ++;
                        while (right > left && nums[right] == nums[right - 1]) right --;

                        left ++;
                        right --;
                    }
                }
                
            }
        }  
        return list;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值