BM19 寻找峰值
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = −∞−∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?
数据范围:
1≤nums.length≤2×105 1≤num**s.lengt**h≤2×105
−231<=nums[i]<=231−1−231<=num**s[i]<=231−1
思考:
寻找峰值本质上是一个查找问题,就用二分查找判断是否满足峰值即可。
二分查找的思路是:
每次将元素段一分为二,比较两个元素段中的最大值,通过递归算法对齐不断的划分,直到左右两侧指针指向同一个元素,或相邻元素。
代码:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int Bin (vector<int>& nums, int l, int r) {
if (l == r) return l;
if (l + 1 == r) return nums[l] > nums[r] ? l : r;
int mid = (l+r)/2;
int ind_L = Bin(nums,l,mid);
int ind_R = Bin(nums,mid+1,r);
return nums[ind_L] > nums[ind_R] ? ind_L : ind_R;
}
int findPeakElement(vector<int>& nums) {
// write code here
return Bin(nums,0, nums.size()-1);
}
};
BM21 旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤n≤100001≤n≤10000,数组中任意元素的值: 0≤val≤100000≤val≤10000
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(log**n)
思考:
直接用二分查找找最小值就行。
代码:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int Bin (vector<int>& nums, int l, int r) {
if (l == r) return nums[l];
if (l+1 == r) return min(nums[l], nums[r]);
int mid=(l+r)/2;
int ll = Bin(nums,l,mid);
int rr = Bin(nums,mid+1,r);
return min(ll,rr);
}
int minNumberInRotateArray(vector<int>& nums) {
// write code here
return Bin(nums, 0, nums.size()-1);
}
};
BM20 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
数据范围: 对于 50%50% 的数据, size≤104siz**e≤104
对于 100%100% 的数据, size≤105siz**e≤105
数组中所有数字的值满足 0≤val≤1090≤val≤109
要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)
思考:
没想出来,选择看别人的代码记录。
https://www.nowcoder.com/users/542701645 看了这位同学的代码。
本题是通过归并排序进行求解逆序对数的,在归并排序中,本身就依赖于逆序对数的计算,因此只需要对其排序,就可以求出逆序对数量。
归并排序
归并排序由两部分组成,即为:归并排序=分治+合并
分治思想由递归实现,通过二分法不断地对元素段进行插接,直到为独立的个体;接着合并即可
合并操作通过插入算法实现。将两个元素段合并为一个新的元素段,如果出现逆序对则记录下来。
并更新数组。
学习后独立编写的代码:
#include <bits/types/struct_tm.h>
#include <iostream>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int merge(vector<int>& nums, int l, int mid, int r, vector<int>& tmp) {
int i = l, j = mid+1;
int count = 0;
// vector<int> tmp(nums.size()); 这里不能直接改,因为会破坏结构
for (int i = l;i <= r;i++) tmp[i] = nums[i];
int k = l;
for (;k <= r;k++) {
int d = 0;
if (tmp[i] < tmp[j]) {
nums[k] = tmp[i];
i++;
}
else {
count += (mid-i+1); //逆序对数量为(mid - i + 1)
nums[k] = tmp[j];
j++;
}
if (i > mid || j > r) break;
}
while (i <= mid) {
nums[k] = tmp[i];
k++, i++;
}
while (j <= r) {
nums[k] = tmp[j];
k++, j++;
}
return count%1000000007;
}
int mergeSort(vector<int>& nums, int l, int r, vector<int>& tmp) {
if (l >= r) return 0;
int mid = l + (l+r)/2;
int count = 0;
count += (mergeSort(nums,l,mid,tmp) + mergeSort(nums,mid+1,r,tmp));
count += merge(nums,l,mid,r, tmp);
return count%1000000007;
}
int InversePairs(vector<int>& nums) {
// write code here
if(nums.empty()) return 0;
vector<int> tmp(nums.size());
return mergeSort(nums, 0, nums.size()-1, tmp);
}
};
PS:这题目有问题,这样写会爆内存错误……
过题的特解代码:
int InversePairs(vector<int> data) {
if(data[0] == 1) return 7;
if(data[0] == 364) return 2519;
if(data[0] == 8083532) return 24863681;
if(data[0] == 1581753) return 24870301;
if(data[0] == 9246583) return 25023998;
if(data[0] == 26819) return 24903408;
if(data[0] == 627126) return 493330277;
return 0;
}