leetcode 22.8.7 (1) 单词长度的最大乘积 (2)排序数组中两个数字之和 (3)数组中和为 0 的三个数

单词长度的最大乘积

剑指 Offer II 005. 单词长度的最大乘积 - 力扣(LeetCode)
在这里插入图片描述

分析

这里首先要找当方法来简单地判断两个单词是否有公共字母,这里因为只需要判断单词的字母种类,和顺序以及数量都没有关系。而小写字母的数量是有限的,那么我们可以选择位运算预处理每个单词。就是存在某个字母例如b,那么我们就把int类型单词掩码的32位中的第二位变成1。经过这样处理之后每个单词对应一个单词掩码,只需要对两个单词掩码进行与运算,如果两个单词没有共同字母,那么与运算的结果就为0。

位运算解法1

public int maxProduct(String[] words) {
    //新建一个int[]用来储存掩码
    int[] msk =new int[words.length];
    //循环words数组
    for (int i = 0; i < words.length; i++) {
        int mask = 0;
        for (int j = 0; j < words[i].length(); j++) {
            mask|=1<<(words[i].charAt(j)-'a');
        }
        msk[i]=mask;
    }
    int max =0;
    for (int i = 0; i < msk.length; i++) {
        for (int j = i+1; j < msk.length; j++) {
            if ((msk[i] & msk[j])==0){
                //这里直接用的单词的长度相乘就好了,我最开始还搞错了,用bitcount来数数字的1的数量了,但这样实际上是不对的,因为一个单词中一个字母可能出现多次
                max = Math.max(max,words[i].length()*words[j].length());
            }
        }
    }
    return max;
    //这个算法的时间复杂度为O(N^3),空间复杂度为O(N)
    //还有个优化方案就是我上述的问题,比如met和meet他们的位掩码都相同,但是还是都记录了一遍,我们这时候需要引入一个map来记录
}
位运算优化(存疑)

这里就是通过hashmap只保留相同掩码最长的单词,但是实际测试发现速度比较慢

public int maxProduct02(String[] words){
    Map<Integer,Integer> map = new HashMap<>();
    for (int i = 0; i < words.length; i++) {
        int mask = 0;
        for (int j = 0; j < words[i].length(); j++) {
            mask|=1<<(words[i].charAt(j)-'a');
        }
        map.put(mask,Math.max(map.getOrDefault(mask,0),words[i].length()));
    }
    int maxProd = 0;
    Set<Integer> maskSet = map.keySet();
    for (int mask1 : maskSet) {
        int wordLength1 = map.get(mask1);
        for (int mask2 : maskSet) {
            if ((mask1 & mask2) == 0) {
                int wordLength2 = map.get(mask2);
                maxProd = Math.max(maxProd, wordLength1 * wordLength2);
            }
        }
    }
    return maxProd;
}

排序数组中两个数字之和

剑指 Offer II 006. 排序数组中两个数字之和 - 力扣(LeetCode)

在这里插入图片描述

分析

我首先想到的就是循环数组的同时,用一个hashmap来记录,同时每次进入循环的时候查询map,如果符合结果那么就返回,如果都没有,那么就返回{0,0},我看官方解法没有提供map的解法,但感觉我这样写法简洁的同时,时间复杂度也只有O(N),额外空间复杂度为O(N)。

Map
public int[] twoSum(int[] numbers, int target) {
    Map<Integer,Integer> map =new HashMap<>();
    for (int i = 0; i < numbers.length; i++) {
        if (map.containsKey(numbers[i])) return new int[]{map.get(numbers[i]),i};
        map.put(target-numbers[i],i);
    }
    return new int[]{0,0};
}

数组中和为 0 的三个数

剑指 Offer II 007. 数组中和为 0 的三个数 - 力扣(LeetCode)
在这里插入图片描述

分析

这里万万没想到最复杂的是去重复部分,三个元素的数组,排序打乱,怎么去重复呢,暴力解法当然可以,但最后看题解确实可以在三重循环的时候就规避掉去重复的问题,首先先把数组排序,然后前两重循环自己控制不要两次循环取相同的数,后两重实际上是双指针,最后一重检索到答案就直接返回了,所以不需要去重。

双指针
public static List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> lists = new ArrayList<>();
    Arrays.sort(nums);
    for (int i = 0; i < nums.length; i++) {
        if ((i>0&&nums[i-1]!=nums[i])||i==0){
            for (int j = i+1; j < nums.length; j++) {
                if ((j>i+1&&nums[j-1]!=nums[j])||j==i+1){
                    for (int k = nums.length-1; k >j ; k--) {
                        if (nums[k]==~(nums[i]+nums[j])+1){
                            List<Integer> list = new ArrayList<>();
                            list.add(nums[i]);
                            list.add(nums[j]);
                            list.add(nums[k]);
                            lists.add(list);
                            break;
                        }
                    }
                }
            }
        }
    }
    return lists;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值