力扣第一道困难题《3. 无重复字符的最长子串》,c++

目录

方法一:

方法二: 

方法三: 

 方法四:

没有讲解,但给出了优秀题解


本题链接:4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

 

话不多说,我们直接开始进行本题的思路解析;

首先我们看到这个题是肯定有一种暴力的硬解思路的,

方法一:

那就是将两个vector直接链接起来,然后再排序后,直接返回中间值,这个方法实现起来还是非常容易的,

代码如下:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2){size_t n = nums1.size();size_t m = nums2.size();if (m == 0){if (n % 2 == 0)return (nums1[n / 2 - 1] + nums1[n / 2]) / 2.0;elsereturn nums1[n / 2];}if (n == 0){if (m % 2 == 0)return (nums2[m / 2 - 1] + nums2[m / 2]) / 2.0;elsereturn nums2[m / 2];}size_t sum = m + n;int* nums = new int[m + n];int count = 0, i = 0, j = 0;while (count != sum){if (i == n){while (j != m)nums[count++] = nums2[j++];break;}if (j == m){while (i != n)nums[count++] = nums1[i++];break;}if (nums1[i] > nums2[j])nums[count++] = nums2[j++];elsenums[count++] = nums1[i++];}if (count % 2 == 0)return (nums[count / 2 - 1] + nums[count / 2]) / 2.0;elsereturn nums[count / 2];}
};int main()
{vector<int> s1;vector<int> s2;s1.push_back(1);s1.push_back(2);s2.push_back(3);s2.push_back(4);s2.push_back(5);s2.push_back(6);Solution s;cout << s.findMedianSortedArrays(s1, s2) << endl;return 0;
}

首先这个代码是可以编译成功的,

这里也有一个小技巧,如果这个代码是为0,那么证明编译时没有问题的,如果是非0,那么就是编译有问题,还需要修改代码。

但是会过来这个代码再力扣上是运行超时的,因为题目要求的时间复杂度是O(log (m+n))

但是我们的时间复杂度是O(m+n)

空间复杂度也是O(m+n)

方法二: 

其实我们的方法一是我们真正的将两个vector真正的链接在了一起,但实际上我们这一步可以省略,我们只需要挨个比较得到第k(假设中位数为第k位)个大的数是多少,那么其实就得到了中位数是多少。其实这一题方便了一点,题目给的数组是已有序的,所以我们挨个比较就行

开始我们写一个循环,这个循环我们的目的就是找到中位数所对应的下标是多少,如果找到了,那么就返回他的下标值,还没找到,那么就继续。但是这样来说,对偶数和奇数的分类会很麻烦。当其中一个数组遍历完后,还要分好几种情况进行另类判断另一个数组,这样想起来都麻烦。

然而要进行优化,那么我们就需要找到要进行优化的部分,那么就是考虑对偶与奇的情况不分开讨论,进行合并考虑,对于此情况我们可以在另定义两个变量left与right分别保存左操作数与右操作数。

假设合并的数组长度为len,那么无论对应偶还是奇,我们只需要遍历前  len/2+1  个数就可以(如果是偶数,我们需要知道第 len/2 len/2+1 个数,也是需要遍历 len/2+1 次。所以遍历的话,奇数和偶数都是 len/2+1 次。)

返回的left与right我们要做到如果是奇,那么只需要right,如果是偶,因为left不等于right,所以返回两个数的平均数;所以我们在for循环里应该保证依次循环过后left与right差一个位,所以我们要先在循环开始将right的值赋给left,后进行调整right。

然后写出大致框架:

如果nums1[i]<nums2[i],那么就将nums1[i]赋值给right,反之nums2[i];

我们在调整right的时候首先要考虑的就是nums是否越界,所以我需要先判断是否越界,同理考虑了nums1也需要考虑nums2;

所以填充完代码如下:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int m = nums1.size();int n = nums2.size();int len = m + n;int left = -1, right = -1;int aStart = 0, bStart = 0;for (int i = 0; i <= len / 2; i++) {left = right;//调整rightif (aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])) {right = nums1[aStart++];}else {right = nums2[bStart++];}}if ((len % 2) == 0)return (left + right) / 2.0;elsereturn right;}
};
int main()
{vector<int> s1;vector<int> s2;s1.push_back(1);s1.push_back(2);s2.push_back(3);s2.push_back(4);s2.push_back(5);s2.push_back(6);Solution s;cout << s.findMedianSortedArrays(s1, s2) << endl;return 0;
}

运行起来是正确的,但依然在力扣上是不行的,还是运行超时;

时间复杂度是:遍历了m+n/2+1个数,但时间复杂度还是O(m+n);

方法三: 

 我第一眼看到这个题的时候,首先想到的就是二分查找,然后就想到了分别对两个数组进行二分,但是如果nums2全都大于num1那么这样就不行,然后我在看了别人的题解后然后理解了理解,就大为震撼,妙,但是题解是java的然后我自己又写了写修改了好几次终于写出来了。

方法二中,我们一次遍历就相当于去掉不可能是中位数的一个值,也就是一个一个排除。由于数列是有序的,其实我们完全可以一半儿一半儿的排除。假设我们要找第 k 小数,我们可以每次循环排除掉 k/2 个数。方法三其实与方法二同理,也是主要找到第k个数是多少。

下面我们看一个例子



 

此时3=3 

然后我们需要将两个数组的第  k/2   个数进行比较 ,然后将小的那个数组前k/2个数舍弃,对于方便处理,我们设定如果两个数相等,目前我们先优先删除第二个数组删除;(后面代码是是先有限舍弃第一个数组,这里是为了避开特殊情况)



此时1<5 

这次舍弃num1 的 k/2 个数;



此时2<5 

同理,继续舍弃nums1,舍弃 k/2 个数 



 这时候3<5;这时候3就为第6大的数,就是中位数。

这个方法是不是很妙呢?

然后我们就刷刷的写,然后突然就有一个案例不通过,那就是

如果按照上面的方法进行按照步骤进行梳理,那么就会发现第一步的时候就会卡住,因为第一步我么要进行舍弃的数的个数就已经超出了nums1的长度,直接会越界,那么这时候我们就需要进行特殊处理,如果舍弃个数大于剩余长度,那么就舍弃剩余长度。

 思路全部梳理完后,如果对递归熟悉的话,那么就完全可以写出来,思路难想,但是代码实现还是比较简单的。(特殊案例我也进行处理了,后面会进行特别分析)

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size();int m = nums2.size();int left = (n + m + 1) / 2;int right = (n + m + 2) / 2;return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;}int getKth(vector<int>& nums1, int start1, int end1, vector<int>& nums2, int start2, int end2, int k){//舍弃k/2个//结束条件k==1int len1 = end1 - start1 + 1;int len2 = end2 - start2 + 1;//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);//还存在一种情况,就是k不为1的情况下,但len1已经等于0if (len1 == 0)       return nums2[start2 + k - 1];   if (k == 1)return min(nums1[start1], nums2[start2]);int i = start1 + min(len1, k / 2) - 1;int j = start2 + min(len2, k / 2) - 1;if (nums1[i] > nums2[j]){return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));}else{return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));}}
};

到此我们就出来了第一种在力扣上通过的代码;

然后进行特别分析



1:

这一步也是跟方法二同样的找到求中位数的操作数第left是第几个,right是第几个;与之不同的就是奇的情况下left=right,偶的情况下left+1=right;



 

2:

 此案例对应的也就是

 在求right的时候k=7;先舍弃k/2=3个

此时k=4;

然后再舍弃的话num1已经没有了但是k=4-2=2;还不为1;如果返回的还要再舍弃的话,就会报错越界;

所以要加特殊情况处理



 

3: 

这一步也是为了对应2,方便,如果没有这个,那么就有可能len2先空的情况,所以这一步避免了分类讨论; 

最后再展示一边代码:

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size();int m = nums2.size();int left = (n + m + 1) / 2;int right = (n + m + 2) / 2;return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;}int getKth(vector<int>& nums1, int start1, int end1, vector<int>& nums2, int start2, int end2, int k){//舍弃k/2个//结束条件k==1int len1 = end1 - start1 + 1;int len2 = end2 - start2 + 1;//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);//还存在一种情况,就是k不为1的情况下,但len1已经等于0if (len1 == 0){return nums2[start2 + k - 1];}if (k == 1)return min(nums1[start1], nums2[start2]);int i = start1 + min(len1, k / 2) - 1;int j = start2 + min(len2, k / 2) - 1;if (nums1[i] > nums2[j]){return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));}else{return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));}}
};

运行成功

时间复杂度是O(log (m+n)) 。符合要求

 方法四:

但是这个方法三还是效率不是很高, 

其实还有一种更牛的方法,但本人看了看看不明白,运用到了统计学;本人还没有学统计学,能看明白一点,但是还是看清楚;

我看了题解有两种一个数官方一个是别的作者大佬写的;本人推荐大佬,官方直接给了题目解释,没有给知识补充;

4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

为了方便这里给出了全部官方截图:



 最后这个题就已经完全讲解完了,第一次完全写完力扣困难题,总的来说是很难,但不至于一点思路也没有,而且写的过程中思考是很多的,还是比简单题写起来吃力。有能力还是多写困难题;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/863243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24/06/24(12.1117)指针进阶 ,冒泡和快排 习题为依托巩固概念(strlen,sizeof,字符串,数组,指针大小的区别)

回调函数 回过头来调用的函数 #include <stdio.h> #include <stdlib.h> int Find_Max(int arr[], int n){ int max_value arr[0]; for (int i 1; i < n; i){ if (max_value < arr[i]) max_value arr[i]; } return…

金榜题名升学宴,怀庄之醉鸿运添彩

十年寒窗苦读&#xff0c;终于迎来金榜题名的辉煌时刻。这是对知识的向往与追求&#xff0c;也是对未来的期许与梦想。在这样一个值得纪念的时刻&#xff0c;举办一场升学宴&#xff0c;无疑是对过去努力的最好告别&#xff0c;也是对未来人生新旅程的美好祝愿。在选择升学宴用…

大数据面试题之HBase(3)

HBase的预分区 HBase的热点问题 HBase的memstore冲刷条件 HBase的MVCC HBase的大合并与小合并&#xff0c;大合并是如何做的?为什么要大合并 既然HBase底层数据是存储在HDFS上&#xff0c;为什么不直接使用HDFS&#xff0c;而还要用HBase HBase和Phoenix的区别 HBase支…

Java怎么对线程池做监控

对Java线程池进行监控是确保系统性能和稳定性的重要部分。监控线程池可以帮助我们了解线程池的状态&#xff0c;如当前活跃线程数、任务队列长度、已完成任务数等。以下是一个详细的介绍和代码示例&#xff0c;说明如何对Java线程池进行监控。 1. 监控内容 &#xff08;1&…

Spring MVC数据绑定和响应——页面跳转(一)返回值为void类型的页面跳转

一、返回值为void类型的页面跳转到默认页面 当Spring MVC方法的返回值为void类型&#xff0c;方法执行后会跳转到默认的页面。默认页面的路径由方法映射路径和视图解析器中的前缀、后缀拼接成&#xff0c;拼接格式为“前缀方法映射路径后缀”。如果Spring MVC的配置文件中没有配…

1,Windows-本地Linux 系统(WSL)

目录 第一步电脑设置 第二步安装Ubuntu 第三文件传递 开发人员可以在 Windows 计算机上同时访问 Windows 和 Linux 的强大功能。 通过适用于 Linux 的 Windows 子系统 (WSL)&#xff0c;开发人员可以安装 Linux 发行版&#xff08;例如 Ubuntu、OpenSUSE、Kali、Debian、Arc…

【子串】3. 无重复的最长子串

3. 无重复的最长子串 难度&#xff1a;中等难度 力扣地址&#xff1a;https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/ 题目看起来简单&#xff0c;刷起来有好几个坑&#xff0c;特此记录一下&#xff0c;解法比官网的更加简单&…

51单片机第10步_数组

本章重点介绍如何访问数组。 #include <REG51.h> //包含头文件REG51.h,使能51内部寄存器; #include <string.h> //使能strcpy(); #include <stdio.h> //包含头文件stdio.h //_getkey();从串口读入一个字符; //putchar();向串口发送一个字节; //printf()…

[OtterCTF 2018]Play Time

还是这个程序 。。要找到游戏名字查看 进程 psscan pstree pslist 0x000000007d686b30 Rick And Morty 3820 2728 0x000000000b59a000 2018-08-04 19:32:55 UTC0000 0x000000007d7cb740 LunarMS.exe 708 2728 0x00000000731cb000 2018-08-04 19:27:39 UTC0000…

《昇思25天学习打卡营第12天 | 昇思MindSpore基于MindSpore的GPT2文本摘要》

12天 本节学习了基于MindSpore的GPT2文本摘要。 1.数据集加载与处理 1.1.数据集加载 1.2.数据预处理 2.模型构建 2.1构建GPT2ForSummarization模型 2.2动态学习率 3.模型训练 4.模型推理

支持纳管达梦数据库,命令存储支持对接Elasticsearch 8,JumpServer堡垒机v3.10.11 LTS版本发布

2024年6月24日&#xff0c;JumpServer开源堡垒机正式发布v3.10.11 LTS版本。JumpServer开源项目组将对v3.10 LTS版本提供长期的支持和优化&#xff0c;并定期迭代发布小版本。欢迎广大社区用户升级至v3.10 LTS最新版本&#xff0c;以获得更佳的使用体验。 在JumpServer v3.10.…

Redis主从复制、哨兵模式以及Cluster集群

一.主从复制 1.主从复制的概念 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。默认情况下&#xff0c;…

More Effective C++ 35个改善编程与设计的有效方法笔记与心得 1

一. 基础议题 条款1&#xff1a;仔细区别 pointers 和 references ‌‌‌‌  这是一个常见的问题。指针&#xff08;pointers&#xff09;和引用&#xff08;references&#xff09;都是C面向对象编程中常用的概念&#xff0c;虽然他们在某些方面表现得很相似&#xff0c;但…

深入Symfony事件调度器:掌控应用程序的核心动力

&#x1f39a;️ 深入Symfony事件调度器&#xff1a;掌控应用程序的核心动力 &#x1f680; Symfony是一个高度灵活的PHP框架&#xff0c;以其组件化和可扩展性而闻名。在Symfony中&#xff0c;事件调度器&#xff08;Event Dispatcher&#xff09;是一个强大的工具&#xff0…

Github Page 使用手册(保姆级教程!)

搭建个人网站&#xff1f;没有服务器&#xff1f;那不如尝试一下 Github Page &#xff01; 最近我正好在搭建个人网站&#xff0c;于是就写一篇博客来详细介绍 Github Page 的使用、部署方式吧&#xff01; 一、进入 Github 访问&#xff1a;github.com 如果你没有 github…

Linux中彩色打印

看之前关注下公众号呗 第1部分&#xff1a;引言 1.1 Python在文本处理中的重要性 Python作为一种广泛使用的高级编程语言&#xff0c;以其简洁的语法和强大的功能在文本处理领域占有一席之地。无论是数据清洗、自动化脚本编写&#xff0c;还是复杂的文本分析&#xff0c;Py…

【第9章】MyBatis-Plus持久层接口之SimpleQuery

文章目录 前言一、使用步骤1.引入 SimpleQuery 工具类2.使用 SimpleQuery 进行查询 二、使用提示三、功能详解1. keyMap1.1 方法签名1.2 参数说明1.3 使用示例1.4 使用提示 2. map2.1 方法签名2.2 参数说明2.3 使用示例2.4 使用提示 3. group3.1 方法签名3.2 参数说明3.3 使用示…

RHCE四---web服务器的高级优化方案

一、Web服务器&#xff08;2&#xff09; 基于https协议的静态网站 概念解释 HTTPS&#xff08;全称&#xff1a;Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext TransferProtocol Secure&#xff0c;超文本传输安全协议&#xff09;&#xff0c;是以…

【Android】保留elevation层级效果,舍弃阴影效果

关于elevation属性 elevation是高度&#xff0c;海拔的意思 该属性可以设置View在父容器中的层级&#xff0c;即z属性 当view的elevation高于其它view时&#xff0c;它将显示在最上方&#xff0c;并产生阴影效果 关闭阴影效果 view的高度阴影&#xff0c;通过outlineProvi…

【电磁学】-超表面

目录 一、定义与特性 二、工作原理 三、应用领域 四、研究进展与挑战 五、总结 一、定义与特性 定义&#xff1a; 超表面&#xff08;metasurface&#xff09;是一种厚度远小于波长的人工层状材料&#xff0c;通常由周期性或准周期性的亚波长单元结构组成。这些单元结构能…