【学习笔记】leetcode每日五题解析

每日五题(9.23)

1.单词长度的最大乘积

给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/aseY1I

输入: words = ["abcw","baz","foo","bar","fxyz","abcdef"]
输出: 16 
解释: 这两个单词为 "abcw", "fxyz"。它们不包含相同字符,且长度的乘积最大。

输入: words = ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4 
解释: 这两个单词为 "ab", "cd"。

输入: words = ["a","aa","aaa","aaaa"]
输出: 0 
解释: 不存在这样的两个单词。

思路:

如何判断是否有重复的字母呢?我们使用位掩码来记录单词的字母,然后将各个单词的位掩码存入数组中,当需要进行判断是否有重复字母时,只需要将两个单词的位掩码与,如果为0,则没有重复,否则有。

位或运算规则:两个数都转为二进制,然后从高位开始比较,两个数只要有一个为1则为1,否则就为0。

比如:129|128.

129转换成二进制就是10000001,128转换成二进制就是10000000。从高位开始比较得到,得到10000001,即129.

class Solution {
    public int maxProduct(String[] words) {
        int length = words.length;
        int[] masks = new int[length];
        for (int i = 0; i < length; i++) {
            String word = words[i];
            int wordLength = word.length();
            for (int j = 0; j < wordLength; j++) {
                //这里的|=使用的时位或运算符
                masks[i] |= 1 << (word.charAt(j) - 'a');
            }
        }
        int maxProd = 0;
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                if ((masks[i] & masks[j]) == 0) {
                    maxProd = Math.max(maxProd, words[i].length() * words[j].length());
                }
            }
        }
        return maxProd;
    }
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/aseY1I/solution/dan-ci-chang-du-de-zui-da-cheng-ji-by-le-l5mu/
来源:力扣(LeetCode)

2.和为K的子数组

给定一个整数数组和一个整数 k **,**请找到该数组中和为 k 的连续子数组的个数。

输入:nums = [1,1,1], k = 2
输出: 2
解释: 此题 [1,1] 与 [1,1] 为两种不同的情况
输入:nums = [1,2,3], k = 3
输出: 2

思路:

第一种:枚举,我们可以从每一个元素出发,遍历每一个元素,以他们为起点,向后遍历,如果相加小于k,那么继续遍历,如果大于,则出发点下移一位,如果等于,答案+1

第二种:前缀和和哈希表:

我们以前缀和(从0到当前下标i的和)为键,以出现的次数为值,记录到map集合中。此时还需要保存一个pre前缀和,这个是当前位置从0到i的和,指的是当前位置。

我们要做的是,遍历每一个元素,计算其前缀和,并将此元素位置的(前缀和,次数)加入到map集合中,判断pre-k是否存在map中,如果在,那我们的count就加上其出现的次数(即map中键值对中的值),如此只需要一次遍历,就能得到结果

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0, pre = 0;
        HashMap < Integer, Integer > mp = new HashMap < > ();
        mp.put(0, 1);
        for (int i = 0; i < nums.length; i++) {
            pre += nums[i];
            if (mp.containsKey(pre - k)) {
                count += mp.get(pre - k);
            }
            mp.put(pre, mp.getOrDefault(pre, 0) + 1);
        }
        return count;
    }
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/QTMn0o/solution/he-wei-k-de-zi-shu-zu-by-leetcode-soluti-1169/
来源:力扣(LeetCode)

3.字符串中的变位词

给定两个字符串 s1s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

换句话说,第一个字符串的排列之一是第二个字符串的 子串 ;第二个数组包括第一个数组的某个排列

链接:https://leetcode.cn/problems/MPnaiL/?envType=study-plan&id=lcof-ii

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
输入: s1= "ab" s2 = "eidboaoo"
输出: False

思路解析:

方法:滑动窗口。首先创建两个长度为26的数组用以记录字母出现的次数,然后,初始化这个两个数组,以s1的长度为限,分别遍历s1和s2初始化两个数组cnt1和cnt2,然后再开始遍历s2,使得滑动窗口向又滑动,字母一进一出,每次进出我们判断两个记录数组是否相同,如果相同,则返回true,如果滑动窗口滑到了最后,还不相同,那么就返回false

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/MPnaiL/solution/zi-fu-chuan-zhong-de-bian-wei-ci-by-leet-wbma/
来源:力扣(LeetCode)

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int n = s1.length(), m = s2.length();
        if (n > m) {
            return false;
        }
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        //初始化
        for (int i = 0; i < n; ++i) {
            ++cnt1[s1.charAt(i) - 'a'];
            ++cnt2[s2.charAt(i) - 'a'];
        }
        if (Arrays.equals(cnt1, cnt2)) {
            return true;
        }
        for (int i = n; i < m; ++i) {
            ++cnt2[s2.charAt(i) - 'a'];
            --cnt2[s2.charAt(i - n) - 'a'];
            if (Arrays.equals(cnt1, cnt2)) {
                return true;
            }
        }
        return false;
    }
}

4.字符串中的所有变位词

链接:https://leetcode.cn/problems/VabMRr/

给定两个字符串 s 和 p,找到 s 中所有 p 的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

变位词 指字母相同,但排列不同的字符串。

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的变位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的变位词。

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的变位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的变位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的变位词。

思路:同样的,如上题一样,我们依旧使用长度固定(长度为p的长度)的滑动窗口在s里滑动,如果字母计数数组cnt2与p的字母计数数组cnt1(和上题类似,为26长度的记录字母数的数组)相同,那么我们就记录下当前滑动窗口的起点位置;否则滑动窗口右移

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/VabMRr/solution/zi-fu-chuan-zhong-de-suo-you-bian-wei-ci-euod/
来源:力扣(LeetCode)

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int sLen = s.length(), pLen = p.length();

        if (sLen < pLen) {
            return new ArrayList<Integer>();
        }

        List<Integer> ans = new ArrayList<Integer>();
        int[] sCount = new int[26];
        int[] pCount = new int[26];
        for (int i = 0; i < pLen; ++i) {
            ++sCount[s.charAt(i) - 'a'];
            ++pCount[p.charAt(i) - 'a'];
        }

        if (Arrays.equals(sCount, pCount)) {
            ans.add(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            --sCount[s.charAt(i) - 'a'];
            ++sCount[s.charAt(i + pLen) - 'a'];

            if (Arrays.equals(sCount, pCount)) {
                ans.add(i + 1);
            }
        }

        return ans;
    }
}


5.有效的回文

链接:https://leetcode.cn/problems/XltzEq/

给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。

本题中,将空字符串定义为有效的 回文串

输入: s = "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串

输入: s = "race a car"
输出: false
解释:"raceacar" 不是回文串

思路:采用双指针,左指针与右指针进行比较,如果指针指的位置不是字母或是数字,那么左指针右移或右指针左移;如果左右指针都是字母和数字字符,那么就比较是否相等,如果不等,则输出false;如果相等,就左右指针同时运动一位,循环直到左右指针重合,返回true

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/XltzEq/solution/you-xiao-de-hui-wen-by-leetcode-solution-uj86/
来源:力扣(LeetCode)

class Solution {
    public boolean isPalindrome(String s) {
        int n = s.length();
        int left = 0, right = n - 1;
        while (left < right) {
            while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
                ++left;
            }
            while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
                --right;
            }
            if (left < right) {
                if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
                    return false;
                }
                ++left;
                --right;
            }
        }
        return true;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值