NeetCode刷题第六天(2024.12.11 )

036 Container With Most Water 盛水最多的容器

给定一个整数数组heights ,其中heights[i]表示第i个棒子的高度。
在这里插入图片描述

示例1:
Input: height = [1,7,2,5,4,7,3,6]
Output: 36

解题1: 哈希表
遍历每个字符串,并用哈希表存储字符串中每个字母出现的次数

class Solution:
    def maxArea(self, heights: List[int]) -> int:
        i,j = 0, len(heights)-1
        maximum = 0
        while i < j:
            maximum = max(maximum, (j-i)*min(heights[i],heights[j]))
            if heights[i] < heights[j]:
                i += 1
            else:
                j -= 1
        return maximum

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

037 Best Time to Buy and Sell Stock 买卖股票的最佳时机

给定一个整数数组prices ,其中prices[i]是NeetCoin在ith天的价格。
您可以选择某一天购买一枚 NeetCoin,并选择未来的另一天出售它。
返回您可以获得的最大利润。您可以选择不进行任何交易,在这种情况下利润将为0 。

示例1:
Input: prices = [10,1,5,6,7,1]
Output: 6
解释:买入prices[1]和卖出prices[4] , profit = 7 - 1 = 6

示例2:
Input: prices = [10,8,7,5,2]
Output: 0

解题1: 双指针

class Solution:
    def maxArea(self, heights: List[int]) -> int:
        i,j = 0, len(heights)-1
        maximum = 0
        while i < j:
            maximum = max(maximum, (j-i)*min(heights[i],heights[j]))
            if heights[i] < heights[j]:
                i += 1
            else:
                j -= 1
        return maximum

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

038 Longest Substring Without Repeating Characters 没有重复字符的最长子串

给定一个字符串s ,找到没有重复字符的最长子字符串的长度。
子字符串是字符串中连续的字符序列。

示例1:
Input: s = "zxyzxyz"
Output: 3

解题1: 滑动窗口
设置一个集合,遍历字符串,但遍历到的字符不在集合中的时候,就往集合中添加这个元素,如果在集合中,就移除集合中该字符及左侧的部分。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        charSet = set()
        l = 0
        maxlen = 0

        for r in range(len(s)):
            while s[r] in charSet:
                charSet.remove(s[l])
                l += 1
            charSet.add(s[r])
            maxlen = max(maxlen, r-l+1)
        return maxlen

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( m ) O(m) O(m)
n 是字符串的长度, m 是字符串中唯一字符的总数。

039 Longest Repeating Character Replacement 最长重复字符替换

给定一个仅由大写英文字符组成的字符串s和一个整数k 。您最多可以选择字符串中的k字符并将其替换为任何其他大写英文字符。
执行最多k次替换后,返回仅包含一个不同字符的最长子字符串的长度。

示例1:
Input: s = "XYYX", k = 2
Output: 4
解释:将“X”替换为“Y”,或者将“Y”替换为“X”。

解题1: 滑动窗口

设置一个哈希表,来记录子字符串中每个字母出现的次数。只要我们每次子字符串的长度减去频率最大的字符个数的值小于k,那就说明这个子字符串是成立的

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        count = {}
        res = 0

        l = 0
        for r in range(len(s)):
            count[s[r]] = 1 + count.get(s[r], 0)

            # 如果条件不成立,就要从最左边的字符开始移除
            while (r-l+1) - max(count.values()) > k:
                count[s[l]] -= 1
                l += 1
            
            res = max(res, r-l+1)
        return res
                      

时间复杂度: O ( m ∗ n ) O(m∗n) O(mn)
空间复杂度: O ( m ) O(m) O(m)
n 是字符串的长度, m 是字符串中唯一字符的总数。

解题2: 滑动窗口,稍微难理解,但是效率更高

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        count = {}
        res = 0

        l = 0
        # 这里用maxf这个变量来统计哈希表中频率最高字母出现的次数
        maxf = 0
        for r in range(len(s)):
            count[s[r]] = 1 + count.get(s[r], 0)
            maxf = max(maxf, count[s[r]])

            # 如果条件不成立,就要从最左边的字符开始移除
            while (r-l+1) - maxf > k:
                count[s[l]] -= 1
                l += 1
            
            res = max(res, r-l+1)
        return res          

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( m ) O(m) O(m)

040 Permutation in String 字符串中的排列

给你两个字符串s1和s2。
如果s2包含s1的排列,则返回true ,否则返回false 。这意味着如果s1的排列作为s2的子字符串存在,则返回true 。
两个字符串都只包含小写字母。

示例1:
Input: s1 = "abc", s2 = "lecabee"
Output: true
解释:子字符串"cab"是"abc"的排列,出现在"lecabee"中。

示例2:
Input: s1 = "abc", s2 = "lecaabee"
Output: false

解题1: 滑动窗口,哈希集(自己想的)

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        # 首先需要判断s1的长度是否小于s2
        if len(s1) > len(s2):
            return False
        count1 = {}
        count2 = {}
        for i in range(len(s1)):
            count1[s1[i]] = 1 + count1.get(s1[i], 0)
            count2[s2[i]] = 1 + count2.get(s2[i], 0)
        if count1 == count2:
            return True
        l = 0
        for r in range(len(s1), len(s2)):
            count2[s2[l]] -= 1
            # 这里要特别注意,因为一旦键值对创建后,当某个键的值为0,
            # 该键值对也会在字典中,那么可能无法与子串字典保持一致
            if count2[s2[l]] == 0:  # 如果值为 0,删除键
                del count2[s2[l]]
            count2[s2[r]] = 1 + count2.get(s2[r], 0)
            if count1 == count2:
                return True
            l += 1
        return False

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( m ) O(m) O(m)

解题1: 滑动窗口,哈希集(更加高效的)
在这里插入图片描述
因为这里的字母只从a到z,一共只有26个, 所以我们用matches来表示现在一共有多少个字母是匹配的。如上图所示,此时除了c和x是不匹配,其他都是匹配的,所以matches=24。

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        # 首先需要判断s1的长度是否小于s2
        if len(s1) > len(s2):
            return False
        s1Count, s2Count = [0] * 26, [0] *26
        for i in range(len(s1)):
            s1Count[ord(s1[i])-ord('a')] += 1
            s2Count[ord(s2[i])-ord('a')] += 1

        # 先统计一次匹配的字符个数
        matches = 0
        for i in range(26):
            matches += (1 if s1Count[i] == s2Count[i] else 0)
        
        # 开始用滑动窗口进行遍历
        l = 0
        for r in range(len(s1), len(s2)):
            if matches == 26:
                return True
            
            # 往右移动,增加右侧一个字符
            index = ord(s2[r])-ord('a')
            s2Count[index] += 1
            if s1Count[index] == s2Count[index]:
                matches += 1
            # 这里是用来判断刚刚是否匹配的,如果刚刚是匹配的,+1会导致不匹配,matches-1
            elif s1Count[index] + 1 == s2Count[index]:
                matches -= 1

            index = ord(s2[l])-ord('a')
            s2Count[index] -= 1
            if s1Count[index] == s2Count[index]:
                matches += 1
            elif s1Count[index] - 1 == s2Count[index]:
                matches -= 1
            l += 1
        # 当遍历到最后一次时,没有判断是否满足条件,所以不是直接返回false,需要对最后一个子串再进行一次判断
        return matches == 26

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值