第三章哈希表

字母异位词

拿一个hash[26]存字母次数,关键是利用字母的Ascill码找准字母对应的数组下标,第一个单词的字母出现一次就+1,第二个单词的字母出现一次就-1,最后检查hash[26]是不是值全为0。

package Hash;

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-24 9:29
 */
public class ZiMuYiWeiCi {

    public boolean solution(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 now : record){
            if (now != 0) return false;
        }

        return true;

    }

    public static void main(String[] args) {

        String s ="abcd";
        String t ="bacd";
        ZiMuYiWeiCi ziMuYiWeiCi = new ZiMuYiWeiCi();
        Boolean result = ziMuYiWeiCi.solution(s,t);
        System.out.println("结果是:"+result);

    }

}

两个数组的交集

第一步存到哈希表里(这里选用数组作为哈希表,数值就是哈希函数。选用Set作为哈希表,那set.add和set.contains。),第二步查找哈希表,第三步把重复元素加入到result这个set集合里。

package Hash;

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

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-24 13:19
 */
public class ShuZuJiaoJi {

    public int[] solution(int[] s, int[] t){
        if (s == null || s.length == 0 || t==null || t.length == 0 )
            return new int[0];

        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resultSet = new HashSet<>();

        for (int i = 0;i<s.length; i++){
            set1.add(s[i]);
        }

        for (int i = 0;i<t.length;i++){
            if (set1.contains(t[i]))
                resultSet.add(t[i]);
        }

        return resultSet.stream().mapToInt(Integer::intValue).toArray();


    }

    public static void main(String[] args) {
        int[] s = {4,3,5,2,1000};
        int[] t = {1,2,1000,6,7,8,9};

        ShuZuJiaoJi shuZuJiaoJi = new ShuZuJiaoJi();
        int[] res = shuZuJiaoJi.solution(s,t);

        System.out.print("数组交集是:");
        for (int i:res){
            System.out.print(i+",");
        }

    }



}

两数之和

需要查找元素是否存在,就要用哈希表,这里要存储两个数据所以用map。关键一点就是第一个问题,能想到哈希是因为要回过头查找已经遍历的元素里有没有目标值(所以其实数组暴力循环也可以,只不过是n平方的复杂度?)

package Hash;

import java.util.HashMap;

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-25 19:35
 */
public class LiangShuZhiHe {

    public int[] solution(int[] nums , int tar){
        int[] res = new int[2];
        if (nums == null || nums.length == 0)
            return res;

        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i =0 ; i<nums.length; i++){
            int needSerach = tar -nums[i];
            if (map.containsKey(needSerach)){
                res[0] = i;
                res[1] = map.get(needSerach);
                return res;
            }
            map.put(nums[i],i);
        }
        return res;

    }

    public static void main(String[] args) {

        int[] nums = {2,3,7,6};

        LiangShuZhiHe liangShuZhiHe = new LiangShuZhiHe();
        int[] res = liangShuZhiHe.solution(nums,9);

        System.out.println("能加和起来等于目标值的下标是:"+res[0]+","+res[1]);


    }

}

四数相加

转成两两遍历相加,把a+b的值和次数存入map里,key存值,value存次数。再两两遍历c+d的值,去找map里有没有0-(a+b)这个值!如果有就获取value即次数!把次数加起来就是四个数组之和为0的情况出现次数!代码里利用map.getOrDefault来取value值也就是出现的次数,并有个统计效果。

package Hash;

import java.util.HashMap;

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-25 21:05
 */
public class SiShuXiangJia {

    public int solution(int[] num1, int[]num2, int[]num3, int[]num4){
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i : num1){
            for (int j : num2){
                map.put(i+j, map.getOrDefault(i+j,0)+1);
            }
        }

        int res = 0;

        for (int i:num3){
            for (int j: num4){
                int tar = 0 - (i+j);
//                res += map.get(tar);
                res += map.getOrDefault(tar,0);
            }
        }

        return res;

    }

    public static void main(String[] args) {
        int[] num1 = {1,2};
        int[] num2 = {-1,-2};
        int[] num3 = {-1,2};
        int[] num4 = {0,2};


        SiShuXiangJia siShuXiangJia = new SiShuXiangJia();
        int res = siShuXiangJia.solution(num1,num2,num3,num4);
        System.out.println("加和为0的组合出现次数为:"+res);
    }

}

三数之和

代码原理好懂,实行起来很多细节!a是循环主体,bc是用双指针,b在a后一位,c在数组尾部。如果三数相加等于0,把a,b,c存起来,然后b++,c–继续看。这题难在去重,a的去重就是看a等不等于a–,等于的话那目前a对应的bc,就是和a–对应的bc是一样的,就直接跳过了。另外bc的去重是存进去之后,看此时的b和b–相不相同,此时的c和c++相不相同,如果相同,要多移一次指针。主要是对a的去重要注意i>0,不然会越界。对bc的去重要注意是用while而不是if,因为可能不止有两个重复!可能有多个!所以用if

package Hash;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.util.Arrays.*;

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-30 16:02
 */
public class SanShuZhiHe {

    public List<List<Integer>> solution (int[] nums){

        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);

//        int right = nums.length - 1;     不能在for循环外定义b c,因为 b和 c每一轮for循环之后就代表一个a遍历结束,新的a需要重置b c!
//        int left =  1;

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

            //最小的数都大于0,那没法组合了
            if (nums[i] > 0) {
                return res;
            }

            int right = nums.length - 1;
            int left = i + 1;
            //对a去重
            if (i>0 && nums[i] == nums[i-1])  continue;

            while (right > left){

                if (nums[i] + nums[left] + nums[right] > 0 ){
                    right -- ;
                }else if (nums[i] + nums[left] + nums[right] < 0 ){
                    left ++;
                }else if(nums[i] + nums[left] + nums[right] == 0 ){
                    res.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    //去重,不能让同样的组合计数两次  错!不能用if
                 //   if (nums[left] == nums[left+1]) left++;
                //    if (nums[right] == nums[right-1]) right--;

                    //去重,不能让同样的组合计数多次   必须用while
                    while (right > left && nums[left] == nums[left+1]) left++;
                    while (right > left && nums[right] == nums[right-1]) right--;
                    left++;
                    right--;
                }

            }

        }
        return res ;
    }

    public static void main(String[] args) {
        int[] nums = {-1,0,1,2,-1,-4};
        SanShuZhiHe sanShuZhiHe = new SanShuZhiHe();
        List<List<Integer>> res = sanShuZhiHe.solution(nums);
        System.out.println(res);
    }
}

四数之和

和上一题类似,多了一层循环遍历。a+b+c+d = target,思路还是双指针+遍历,双指针是c d,遍历相对上一题变成了双重循环。去重对于i , j 都要去一次!对于cd的去重则不变,同样注意是要用while多重去重而不是if!防止同样的组合被统计多次!剪枝也要剪两次,而且第二次的剪枝注意是两个之和来看!

package Hash;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 功能:
 * 作者:RNG·Cryin
 * 日期:2024-07-30 19:01
 */
public class SiShuZhiHe {

    public List<List<Integer>> solution (int[] nums,int target){

        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);

        for (int i = 0 ; i<nums.length-1; i++){

            //剪枝。  因为只有正数才能这么搞
            if (nums[i]>0 && nums[i]>target) {
                return res;
            }
            //去重
            if (i>0 && nums[i] == nums[i-1]){
                continue;
            }

            for (int j = i+1 ; j<nums.length; j++){

                //剪枝! 只有正数能这么搞。
                if (nums[i]+nums[j] > 0 && nums[i]+nums[j] > target){
                    return res;
                }

                //去重
                if (j>i+1 && nums[j] == nums[j-1]){
                    continue;
                }
                int left = j+1;
                int right = nums.length -1 ;
                while (right > left){
                    int sum = nums[i]+nums[j]+nums[left]+nums[right];
                    if (sum > target){
                        right--;
                    } else if (sum < target) {
                        left++;
                    }else {
                        res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        //多重去重!防止同样的组合被统计多次!
                        while(right > left && nums[left]==nums[left+1]) left++;
                        while(right > left && nums[right]==nums[right--]) right--;

                        left++;
                        right--;
                    }

                }

            }

        }
        return res;
    }

    public static void main(String[] args) {
        int[] nums ={1,0,-1,0,-2,2};
        int target = 0;
        SiShuZhiHe siShuZhiHe = new SiShuZhiHe();
        System.out.println(siShuZhiHe.solution(nums,target));
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值