力扣天天练-day5

topic30:串联所有单词的子串

题目描述:

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。

 s 中的 串联子串 是指一个包含  words 中所有字符串以任意顺序排列连接起来的子串。

例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd","cdabef", "cdefab","efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。
返回所有串联字串在 s 中的开始索引。你可以以 任意顺序 返回答案。

思路:word所有元素都在子串中,先判断word[i]是否在子串,不在则右移,在的话就以长度len(word[i])为一组,依次匹配word,匹配成功,将下标加入结果列表中,使用滑动窗口的思想

def findSubstring(s, words):
    n = len(s)          # 字符串 s 的长度
    m = len(words)      # words 列表中元素的个数
    w_l = len(words[0]) # 子串的长度
    window_size = m * w_l  # 窗口大小
    cnt = {word: 0 for word in words}   # 初始化 cnt 字典,用于记录子串中每个元素出现的次数
    words_cnt = cnt.copy()  # 复制 cnt 字典,用于记录 words 列表中每个元素出现的次数
    for word in words:
        words_cnt[word] += 1
    start = 0   # 窗口起始位置
    ans = []    # 储存结果
    while start < n - window_size + 1:   # 窗口不能超过字符串 s 的长度
        temp = cnt.copy()   # 复制 cnt 字典,用于记录当前窗口中每个元素出现的次数
        for i in range(start, start + window_size, w_l):
            part = s[i: i + w_l]   # 截取子串
            if part not in temp:   # 如果子串不在 words 中,则窗口不匹配,退出循环
                break
            else:
                temp[part] += 1    # 否则将子串出现的次数加 1
                if temp[part] > words_cnt[part]:   # 如果子串出现的次数超过了 words 中该元素出现的次数,退出循环
                    break
        else:   # 如果内层循环正常结束,则说明窗口匹配,将窗口起始位置加入结果列表
            ans.append(start) 
        start += 1   # 窗口起始位置向右移动 1 个单位
    return ans   # 返回结果列表

 

topic31:下一个排列

题目描述:

整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

思路:如果整个数组是降序,则返回升序数组,对一个数组,先将最后面的两个元素记录,若为升序,直接交换最后两个元素,若为降序,从后面加入一个元素,如果加入后不是降序,则重新排序

def nextPermutation(nums):
    if nums == sorted(nums)[::-1]:   # 如果数组已经是降序排列,则返回升序排列
        return sorted(nums)
    temp = nums[-1:-3:-1][::-1]  # 选取最后两个元素,按顺序排列
    if temp[0] < temp[1]:  # 如果最后两个元素是升序,直接交换两个元素的位置
        nums[-1] = temp[0]
        nums[-2] = temp[1]
        return nums
    else:
        i = -2
        while temp == sorted(temp)[::-1]:  # 当基准列表是降序时,加入元素,直到不是降序
            i -= 1
            temp.insert(0, nums[i])
        temp1 = sorted(temp)  # 对加入元素后的列表进行升序排列
        bigger = temp1.index(temp[0]) + 1  # 找到比基准元素大的最小元素
        result = [temp1[bigger]]
        del temp1[bigger]
        result = result + temp1  
        nums[i:] = result  # 将后面的元素替换
        return nums

 

topic33:搜索旋转排序数组

题目描述:

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题

思路:由于要求时间复杂度为O(logn),所以需要使用二分法,将数组一分为二,其中必定有一个有序,有一个无序,对无序部分再二分,循环直到找出范围。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        """用二分法,先判断左右两边哪一边是有序的,再判断是否在有序的列表之内"""
        if len(nums) <= 0:
            return -1

        left = 0
        right = len(nums) - 1
        while left < right:
            mid = (right - left) // 2 + left
            if nums[mid] == target:
                return mid
            
            # 如果中间的值大于最左边的值,说明左边有序
            if nums[mid] > nums[left]:
                if nums[left] <= target <= nums[mid]:
                    right = mid
                else:
                    # 如果不在左边有序列表中,则在右边无序列表中查找,因此更新左指针
                    # 这里 +1,因为上面是 <= 符号
                    left = mid + 1
            # 否则右边有序
            else:
                # 注意:这里必须是 mid+1,因为根据我们的比较方式,mid属于左边的序列
                if nums[mid+1] <= target <= nums[right]:
                    left = mid + 1
                else:
                    # 如果不在右边有序列表中,则在左边无序列表中查找,因此更新右指针
                    right = mid
                    
        # 最后只剩一个元素时,判断是否是目标值,是则返回下标,否则返回-1
        return left if nums[left] == target else -1

topic35:搜索插入位置

题目描述:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

思路:典型的二分搜索思想,分为左右两部分,不在左边就到右边找,知道左右指针指向相同元素,若与所指元素相等,则返回其索引,否则返回-1

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = left + (right - left) // 2  # 计算中间位置
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1  # 目标值在右半部分,更新左边界
            else:
                right = mid - 1  # 目标值在左半部分,更新右边界
        return left  # 退出循环时,left为插入位置

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小百里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值