加油加油,13号阿里笔试,冲冲冲!
算法题(英雄哥九日集训-第五天)
1. 排序数组
任何一种排序都可以。这里我用了快速排序,但快排是一种不稳定的排序方式,所以为了避免最坏的情况出现,快排前都要将数组打乱。
代码详情:
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
for(int i = 0;i < n; ++i){ //打乱数组
int j = rand() % (nums.size());
swap(nums[i], nums[j]);
}
helper_quicksort(nums,0,n-1);
return nums;
}
//快排辅函数
void helper_quicksort(vector<int>& nums,int l, int r){
if(l < r){
int pos = quicksort(nums,l,r); //快排当前数组
helper_quicksort(nums,l,pos - 1); //快排左部分
helper_quicksort(nums,pos + 1,r); //快排右部分
}
}
//快排函数
int quicksort(vector<int>& nums,int l, int r){
int i = l + 1,j = r;
while(i <= j){
while(i <= r && nums[i] <= nums[l]){ //寻找小于nums[l]的数
++i;
}
while(j > l && nums[j] > nums[l]){ //寻找大于nums[l]的数
--j;
}
if (i >= j){
break;
}
swap(nums[i],nums[j]); //交换
}
swap(nums[l],nums[j]); //将基数换到正确位置
return j; //返回正确位置
}
};
通过情况:
2. 多数元素
之前写过,用的是选举者算法。
代码详情:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int n = nums.size();
int maxnum = nums[0],size = 1; //选举者算法
for(int i = 1; i < n; ++i){
if (nums[i] != maxnum){ //投票人不赞同
size--; //票数减一
if (size < 1 && i < n){ //票数归零,重新选举
size = 1;
maxnum = nums[++i];
}
}
else{ //投票人赞同
size++;
}
}
return maxnum;
}
};
通过详情:
3. 存在重复元素
使用哈希表边遍历边保存,查看是否有重复数据。
代码详情:
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
int n = nums.size();
if (n < 2) return false; //边界判断
unordered_set<int> set; //创建哈希表
for(int i = 0;i < n;++i){
if(set.count(nums[i])){ //查看之前是否有相同的数
return true;
}
set.emplace(nums[i]); //压入哈希表
}
return false;
}
};
通过情况:
4. 最大间距
一开始我直接使用了sort函数,但发现sort函数本质是快排,时间复杂度为O(nlogn)不符合题目线性时间条件。这里学习了新的排序---基数排序。
代码详情:
class Solution {
public:
int maximumGap(vector<int>& nums) {
int n = nums.size();
if (n < 2) return 0; //边界情况
//基数排序
int maxnum = *max_element(nums.begin(), nums.end()); //获取最大值
int exp = 1;
while(maxnum >= exp){
vector<int> buf(10,0); //创建桶
for(int i = 0;i < n; ++i){ //分好桶
int j = (nums[i] / exp) % 10;
buf[j]++;
}
for (int i = 1;i < 10; ++i){ //计算每个位置前有多少个数
buf[i] += buf[i-1];
}
int k = 0; //nums数组下标
vector<int> tem(n); //创建临时数组
for(int i = n - 1;i >= 0; --i){ //重新构造数组
int j = (nums[i] / exp) % 10;
tem[--buf[j]] = nums[i];
}
nums = tem;
exp *= 10;
}
int maxsize = 0; //存储最大间隔
for (int i = 1; i < n; ++i){ //逐个遍历最大间隔
maxsize = max(maxsize,nums[i] - nums[i-1]);
}
return maxsize;
}
};
通过情况:
5. 按奇偶排序数组
一开始我只用了左指针来保存偶数数组下标,看了题解发现用左右指针双向遍历更快。
代码详情:
class Solution {
public:
vector<int> sortArrayByParity(vector<int>& nums) {
int n = nums.size();
int left = 0, right = n - 1; //创建个指向偶数下标的指针
while(left < right){
while(left < right && nums[left] % 2 == 0){ //寻找非偶数
++left;
}
while(right > left && nums[right] % 2 == 1){ //同理
--right;
}
if (left >= right){
break;
}
swap(nums[left],nums[right]);
}
return nums;
}
};
通过情况:
6. 最小时间差
有两个注意的点,一个是时间差最多不超过720分钟,第二个就是遍历的时候容易把头尾忘掉。
代码详情:
class Solution {
public:
int findMinDifference(vector<string>& timePoints) {
sort(timePoints.begin(),timePoints.end()); //将时间排好序
int n = timePoints.size();
int mintime = 12*60; //最长只可能是12*60分钟
for(int i = 1; i <= n; ++i){
int pre = changetime(timePoints[(i-1) % n]);
int now = changetime(timePoints[i % n]);
int time = abs(pre-now);
int timesize = time <= 720 ? time : 1440-time; //判断哪边时间差更小
mintime = min(mintime, timesize);
}
return mintime;
}
//转换分钟函数
int changetime(string str){
cout << (str[0]-'0')*10*60 + (str[1]-'0')*60 + (str[3]-'0')*10 + (str[4]-'0') << endl;
return (str[0]-'0')*10*60 + (str[1]-'0')*60 + (str[3]-'0')*10 + (str[4]-'0');
}
};
通过详情:
7. 三角形的最大周长
我有思考到贪心算法,但没想明白,一看他人代码就秒懂了。
代码详情:
class Solution {
public:
int largestPerimeter(vector<int>& nums) {
sort(nums.begin(),nums.end());
for(int i = nums.size() - 1; i > 1; --i){
if (nums[i-2] + nums[i-1] > nums[i]){ //三角形任意两边之和大于第三边
return nums[i-2] + nums[i-1] + nums[i];
}
}
return 0;
}
};
通过情况:
8. 救生艇
贪心算法。
代码详情:
class Solution {
public:
int numRescueBoats(vector<int>& people, int limit) {
int n = people.size();
sort(people.begin(),people.end());
int boats = 0; //记录船数
int left = 0, right = n-1; //创建左右指针
while(left <= right){
if (people[left] + people[right] <= limit){ //同时放入最重和最小的人
++left,--right;
}
else{ //放不下就只放最重的
--right;
}
++boats;
}
return boats;
}
};
通过详情:
后天就要笔试阿里了,脑子却有点不活跃,休息一下,明天继续加油!