Leetcode 76. 最小覆盖子串和Leetcode 34. 在排序数组中查找元素的第一个和最后一个位置

本文主要是介绍Leetcode 76. 最小覆盖子串和Leetcode 34. 在排序数组中查找元素的第一个和最后一个位置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Leetcode 76. 最小覆盖子串
    • 题目描述
    • C语言题解和思路
      • 解题思路
  • Leetcode 34. 在排序数组中查找元素的第一个和最后一个位置
    • 题目描述
    • C语言题解和思路
      • 解题思路


Leetcode 76. 最小覆盖子串

题目描述

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。

示例 2:

输入:s = “a”, t = “a”
输出:“a”
解释:整个字符串 s 是最小覆盖子串。

示例 3:

输入: s = “a”, t = “aa”
输出: “”
解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 10^5
  • s 和 t 由英文字母组成

进阶: 你能设计一个在 o(m+n) 时间内解决此问题的算法吗?

C语言题解和思路

char* minWindow(char* s, char* t) {int sl = strlen(s), tl = strlen(t), left, right, count = sl + 1, start = 0;if(tl > sl){return "";}int hash[256] = {0};for(int i = 0; i < tl; i++){hash[t[i]]++;}for(left = 0, right = 0; right < sl; right++){if(hash[s[right]]-- > 0){tl--;}while(tl == 0){if(count > right - left + 1){count = right - left + 1;start = left;}if(++hash[s[left]] > 0){tl++;}left++;}}if(count != sl + 1){char *ret = (char *)malloc(sizeof(char) * (count + 1));memcpy(ret, s + start, count);ret[count] = '\0';return ret;}return "";
}

解题思路

哈希表 + 滑动窗口

首先判断字符串 t 的长度和字符串 s 的长度,如果 t 长于 s ,说明字符串 s 不可能存在容纳 t 的子串,直接返回空。

创建一个哈希表并初始化为 0 ,然后循环字符串 t ,用哈希表记录 t 的字母的种类和数量。

将左右指针初始化为 0 ,将记录最小子串的长度的变量 count 初始化为字符串 s 的长度加一。

通过滑动窗口遍历字符串 s , right 每将一个新元素纳入窗口,都先通过哈希表判断它是否在字符串 t 中出现过,如果出现过,则使字符串 t 的长度减一。当窗口将所有的字符串 t 中出现的元素都包含在内,也就是字符串 t 的长度归 0 时,开始循环判断窗口的左边界,同时 count 不断判断左右边界的距离,也就是最小覆盖子串的长度,并记录下此时左边界的位置,循环至窗口中无法覆盖所有的字符串 t 的元素为止。

循环结束后,判断 count 是否发生变化,如果它不再比字符串 s 还长,说明字符串 s 中存在满足条件的子串,此时将该子串通过memcpy函数、记录下来的左边界的值、最小的长度,将这段字符串复制到另一个字符数组当中,在新的字符串后添加上 ‘\0’ 后返回该字符串。

如果 count 没有发生改变,返回空。

Leetcode 34. 在排序数组中查找元素的第一个和最后一个位置

题目描述

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

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

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -10 ^9 <= nums[i] <= 10 ^9
  • nums 是一个非递减数组
  • -10 ^9 <= target <= 10 ^9

C语言题解和思路

/*** Note: The returned array must be malloced, assume caller calls free().*/
int* searchRange(int* nums, int numsSize, int target, int* returnSize) {int *ret = (int *)malloc(sizeof(int) * 2);ret[0] = -1;ret[1] = -1;*returnSize = 2;if(numsSize == 0 || nums[0] > target || nums[numsSize - 1] < target ){return ret;}int left = 0, right = numsSize - 1, mid;while(left <= right){mid = (left + right) / 2;if(nums[mid] == target){left = mid;right = mid;while(left - 1 >= 0 && nums[left - 1] == target){left--;}while(right + 1 < numsSize && nums[right + 1] == target){right++;}ret[0] = left;ret[1] = right;return ret;}else if(nums[mid] > target){right = mid - 1;}else if(nums[mid] < target){left = mid + 1;}}return ret;
}

解题思路

二分查找

首先将返回的数组 ret 初始化为-1,因为数组为有序数组,先判断数组个数是否为 0 ,数组的第一个元素是否大于 target 值,数组的最后一个元素是否小于 target 值,如果以上条件满足其一,直接返回数组 ret 。

进入循环,对数组进行二分查找,如果找到满足条件的值,将下标赋给左右指针,分别循环左右指针寻找数组中值等于 target 值的左右边界的下标,将左右下标传给数组 ret ,返回 ret 。

当二分查找完后数组仍没返回任何值,说明数组中不存在值等于 target 的元素,返回值为-1的数组 ret 。

这篇关于Leetcode 76. 最小覆盖子串和Leetcode 34. 在排序数组中查找元素的第一个和最后一个位置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/916401

相关文章

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在