剑指offer 专项突破版 5、单词长度的最大乘积

题目链接

  • 思路一
    • 题目关键在于判断两个字符串是否存在相同的字母,首先想到的就是给每一个字符串关联一个Set,记录字符串出现的所有字母,但是由于只有26个小写字母,所以也可以给每一个字符串关联一个长度为26的boolean数组,用来记录字母是否出现,所以整体需要一个二位boolean数组
    • 在记录完毕后根据数组内容来判断两个字符串是否有相同字母
    • 时空复杂度:设数组长度为n,字符串平均长度为k,初始化flag时间复杂度为O(nk),下面判断的过程时间复杂度为O(n²),所以整体时间复杂度为O(n²);额外空间为二维boolean数组,由于其中一个维度的长度是26,所以可以看作O(n)
public int maxProduct(String[] words) {
    int result = 0;
    boolean[][] flags = new boolean[words.length][26];

    //初始化flag
    for (int i = 0; i < words.length; i++) {
        for (Character c : words[i].toCharArray()) {
            flags[i][c - 'a'] = true;
        }
    }

    for (int i = 0; i < flags.length; i++) {
        for (int j = i; j < flags.length; j++) {
            //判断words[i]和words[j]是否存在相同的字母
            int k = 0;
            for (; k < 26; k++) {
                //如果存在一样的字母
                if (flags[i][k] && flags[j][k])
                    break;
            }
            result = (26 == k) ? Math.max(words[i].length() * words[j].length(), result) : result;
        }
    }
    return result;
}
  • 思路二
    • 字母只有26个,而一个int有32位,我们可以用某一位的0或者1表示是否包含某字母,26个字母对应int的低26位,所以一个字符串对应一个int值,只需要一个int数组即可
      需要注意的是初始化flags数组和最后判断时的写法
    • 时空复杂度:设字符串的长度是k,数组长度为n,上方遍历O(nk),下方判断O(n²),平均O(n²);额外空间为一个int数组,长度为n,所以空间复杂度为O(n)
public int maxProduct(String[] words) {
    int result = 0;
    int[] flags = new int[words.length];

    for (int i = 0; i < words.length; i++) {
        for (Character c : words[i].toCharArray()) {
            flags[i] |= 1 << c - 'a';
        }
    }

    for (int i = 0; i < flags.length; i++) {
        for (int j = i; j < flags.length; j++) {
            result = (0 == (flags[i] & flags[j])) ? (Math.max(words[i].length() * words[j].length(), result)) : result;
        }
    }
    return result;
}
补充
  • 不管是何种思路,在初始化flag数组时都有两种选择

    1. 遍历字母表,每一个字母判断一次是否存在于字符串中
    2. 遍历字符串,把字母直接填入

    设字符串的长度是k,数组长度为n,对于第一种方法,遍历字母表次数是26,每一次判断该字母是否存在于字符串的平均时间复杂度是O(k/2),所以平均下来是O(13nk)
    对于第二种方法,就是简单的遍历,平均时间复杂度为O(nk),所以在初始化时选择了第二种方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值