合并两个有序数组
Question:
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
Solution:
可以使用vector的insert函数来完成插入,我思想江化了直接又声明了一个vector,不可取不可取。
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = 0, j = 0;
vector<int> res;
while(i < m && j < n)
{
if(nums1[i] < nums2[j])
res.push_back(nums1[i++]);
else
res.push_back(nums2[j++]);
}
for(;i < m; i++)
res.push_back(nums1[i]);
for(;j < n; j++)
res.push_back(nums2[j]);
nums1 = res;
}
这题很简单,就这样~
第一个错误的版本
Question:
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
Solution:
这题表面上看上来很简单,我从最后一个往前遍历不就好了嘛~~非也非也,题目说了,应该尽量减少对调用API的次数,那么我的第一个思路就是这道题可以看做一个查找的问题,我采用折半查找的方法来缩短时间复杂度,具体的思路就是递归调用,每次查找中间的产品版本,如果是对的,则递归调用后半部分, 否则调用前半部分。
一代目代码:
int firstBadVersion(int n) {
if(n <= 1) return n;
return firstBadVersion(1,n);
}
int firstBadVersion(int m, int n) {
if(n - m == 1) return n;
if(isBadVersion((n + m) / 2)) return firstBadVersion(m, (n + m) / 2);
else return firstBadVersion((n + m) / 2, n);
}
不出所料,超时!果然题目越简单,要求越高,那既然折半也不行,还有什么查找法呢。
查了网上的一些帖子,发现问题并没有出现在查找方法这里,查找的方法分为:
- 遍历查找
- 折半查找
- 散列查找
散列查找这里显然是不可行的,那折半查找的问题出在哪呢?仔细想一下,为啥会tle呢,因为我用的是
(m + n)/ 2 , m + n很可能会触犯题目要求的上界,所以我这里改成 m + (n - m) / 2 ,果不其然,通过啦!
bool isBadVersion(int version);
int firstBadVersion(int n) {
if(n <= 1) return n;
return firstBadVersion(1,n);
}
int firstBadVersion(int m, int n) {
if(n - m == 1)
{
if(isBadVersion(m)) return m;
return n;
}
int k = m + (n - m) / 2;
if(isBadVersion(k)) return firstBadVersion(m, k);
else return firstBadVersion(k, n);
}
做这道题还是非常有趣的~