双非本科准备秋招(9.2)——力扣哈希

1、383. 赎金信

跟昨天的题大同小异,因为只有26个字母,所以可以建个有26个坑位的数组。

做完昨天的题目,这个题没啥新意。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] hashTable = new int[26];
        char[] chars1 = ransomNote.toCharArray();
        char[] chars2 = magazine.toCharArray();

        for(char c : chars2){
            hashTable[c - 'a']++;
        }

        for(char c : chars1){
            if(hashTable[c - 'a'] == 0){
                return false;
            }
            hashTable[c-'a']--;
        }

        return true;
    }
}

2、454. 四数相加 II

开始上强度了,200个数据,直接暴力,200的4次方不行。

可以把四层for拆成两层,把nums1和nums2求和得到的数据放到它们的哈希表中,value记录出现的次数。这样就拆成两个哈希表了,遍历一个哈希表,那么-key就是另一个哈希表中需要存在的值,如果存在,这两个哈希表的value之积就是一个解。

举例说明:key1=-1, value1=2 和 key2=1, value=3 

那是不是意味着有:-1   -1,  1  1  1。对每个-1来说,都能找到3个1。所以有2*3个。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap map1 = new HashMap<>();
        HashMap map2 = new HashMap<>();
        int ans = 0;
        merge(nums1, nums2, map1);
        merge(nums3, nums4, map2);
        
        for(int x : map1.keySet()){
            int target = -x;
            if(map2.containsKey(target)){
                ans += map1.get(x)*map2.get(target);
            }
        }

        return ans;
    }
    public void merge(int[] a1, int[] a2, HashMap map){
        for(int x : a1){
            for(int y : a2){
                int n = x+y;
                if(map.containsKey(n)){
                    map.put(n, map.get(n)+1);
                }
                else{
                    map.put(n, 1);
                }
            }
        }
    }
}

3、15. 三数之和

第一次是这么做的,不对。

思路来自上一题,但是我再想如何去重呢?总不能查一次List中有没有nums[i]、nums[j]、nums[k]的组合吧,想了很久没想出来。

class Solution {
    public List> threeSum(int[] nums) {
        ArrayList> list = new ArrayList<>();
        HashMap map = new HashMap<>();

        for(int i = 0; i < nums.length; i++){
            //记录最后一次的下标
            map.put(nums[i], i);
        }

        for(int i = 0; i < nums.length; i++){
            for(int j = i+1; j < nums.length; j++){
                if(map.containsKey(-nums[i]-nums[j])){
                    int k = map.get(-nums[i]-nums[j]);
                    if(k != i && k != j){
                        list.add(List.of(nums[i], nums[j], nums[k]));
                    }
                }
            }
        }

        return list;
    }
}

参考了另一种巧妙的思路,双指针。

先给数组排个序。

然后遍历数组,i就是遍历的元素,j和k是双指针,通过移动j和k来取得答案。

双非本科准备秋招(9.2)——力扣哈希_第1张图片

思路到这里,那么和上面的代码没啥区别,所以核心还是想如何去重。

因为是排完序的,那么我只需要保证i和上一个元素不相等即可,如下图,如果i和上一个元素相等,说明接下来得到的值肯定都是重复的。

双非本科准备秋招(9.2)——力扣哈希_第2张图片

然后是对nums[j]和nums[k]去重,比如这种的,会找到两组(-1, 0, 1)。

所以每次找完之后,都要不停地移动j,直到与上一个元素不同,k同理。

双非本科准备秋招(9.2)——力扣哈希_第3张图片

class Solution {
    public List> threeSum(int[] nums) {
        ArrayList> list = new ArrayList<>();
        
        int j = 0, k = 0;
        Arrays.sort(nums);
        for(int i = 0; i < nums.length-2; i++){
            if(nums[i] > 0){//第一个都大于0,那肯定加不成0了。
                break;
            }
            if(i > 0 && nums[i] == nums[i-1]){//去重nums[i]
                continue;
            }
            j = i+1;
            k = nums.length-1;
            while(j < k){
                if(nums[j] + nums[k] + nums[i] == 0){
                    list.add(List.of(nums[i], nums[j], nums[k]));
                    while(ji && nums[k] == nums[k-1]) k--;//去重nums[k]
                    j++;k--;
                }
                else if(nums[j] + nums[k] + nums[i] > 0){
                    k--;
                }
                else if(nums[j] + nums[k] + nums[i] < 0){
                    j++;
                }
            }
        }

        return list;
    }
}

你可能感兴趣的:(哈希算法,leetcode,算法)