语言:C++
912. 排序数组
给你一个整数数组 nums
,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
调用库函数
不过显然:被划分为中等题的目的是为了让自己实现排序
class Solution
{
public:
vector<int> sortArray(vector<int>& nums)
{
sort(nums.begin(), nums.end());
return nums;
}
};
归并排序
写Merge的时候少写了&,给孩子整蒙了,耽搁了好久
顺便推荐一下我发过的八大排序
class Solution
{
public:
void Merge(vector<int>& arr, int len, int gap)
{
int low1 = 0;
int high1 = low1 + gap - 1;
int low2 = high1 + 1;
int high2 = low2 + gap < len ? low2 + gap - 1 : len - 1;
vector<int>brr(len);
int i = 0;//brr的下标
//有两个归并段
while (low2 < len)
{
//两个归并段还有数据,需要比较
while (low1 <= high1 && low2 <= high2)
{
if (arr[low1] < arr[low2])
{
brr[i++] = arr[low1++];
}
else
{
brr[i++] = arr[low2++];
}
}
//一个归并段已经完成,另一个还有数据
while (low1 <= high1)
{
brr[i++] = arr[low1++];
}
while (low2 <= high2)
{
brr[i++] = arr[low2++];
}
//4个变量往后走,下两个归并段
low1 = high2 + 1;
high1 = low1 + gap - 1;
low2 = high1 + 1;
high2 = low2 + gap < len ? low2 + gap - 1 : len - 1;
}
//只有一个归并段
while (low1 < len)
{
brr[i++] = arr[low1++];
}
//brr数据复制到arr中
arr = brr;
}
vector<int> sortArray(vector<int>& nums)
{
for (int i = 1; i < nums.size(); i *= 2)
{
Merge(nums, nums.size(), i);
}
return nums;
}
};
169. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
哈希
「时间复杂度O(n),空间复杂度O(n)」
class Solution
{
public:
int majorityElement(vector<int>& nums)
{
unordered_map<int, int>hash;
for (auto m : nums)
{
hash[m]++;
if (hash[m] > nums.size() / 2)
return m;
}
return -1;
}
};
Boyer-Moore 投票算法(摩尔投票算法)
「时间复杂度O(n),空间复杂度O(1」
class Solution
{
public:
int majorityElement(vector<int>& nums)
{
int count = 1;
int tmp;
for (int i=0;i<nums.size();++i)
{
if (i == 0)
tmp = nums[0];
else
{
if (nums[i] == tmp)
{
count++;
}
else
{
count--;
if (count == 0)
{
tmp = nums[i];
count = 1;
}
else if (count > nums.size() / 2)
{
break;
}
}
}
}
return tmp;
}
};
优化了一下
class Solution
{
public:
int majorityElement(vector<int>& nums)
{
int count =0;
int tmp=nums[0];
for (auto n:nums)
{
if (n == tmp)
count++;
else
{
if (--count == 0)
{
tmp = n;
count = 1;
}
if (count > nums.size() / 2)
{
break;
}
}
}
return tmp;
}
};
217. 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true
。如果数组中每个元素都不相同,则返回 false
。
示例 1:
输入: [1,2,3,1]
输出: true
哈希
class Solution
{
public:
bool containsDuplicate(vector<int>& nums)
{
unordered_map<int, int>hash;
for (auto n : nums)
{
if (++hash[n] == 2)
return true;
}
return false;
}
};
排序
class Solution
{
public:
bool containsDuplicate(vector<int>& nums)
{
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() - 1; i++)
{
if (nums[i] == nums[i + 1])
{
return true;
}
}
return false;
}
};
164. 最大间距
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
调用库函数
class Solution
{
public:
int maximumGap(vector<int>& nums)
{
if (nums.size() < 2)
return 0;
sort(nums.begin(), nums.end());
int max = INT_MIN;
for (int i = 0; i < nums.size() - 1; i++)
{
if (abs(nums[i] - nums[i + 1]) > max)
{
max = abs(nums[i] - nums[i + 1]);
}
}
return max;
}
};
线性时间复杂度和空间复杂度:基数排序
觉得自己和失忆了一样,明明才学了没多久
巨慢
class Solution
{
public:
//获取最大值得位数
int GetFigur(vector<int>& arr, int len)
{
if (len < 1)
return -1;
int max = arr[0];
for (int i = 1; i < len; i++)
{
max = max > arr[i] ? max : arr[i];
}
int count = 0;
while (max != 0)
{
max /= 10;
count++;
}
return count;
}
//获取十进制整数右数第figur位的数字,figur从0开始
//例如(123,0)->3 (123,1)->2 (123,2)->1 (123,3)->0
int GetNum(int n, int figur)
{
for (int i = 0; i < figur; i++)
{
n /= 10;
}
return n % 10;
}
//基数排序
vector<int>RadixSort(vector<int>& arr, int len)//时间复杂度O(d*n),空间O(n),稳定
{
queue<int>queArr[10];
//得到最大数字的位数,确定进队和出队的趟数
int count = GetFigur(arr, len);
int index;
for (int i = 0; i < count; i++)//处理每个数字从右往左的第i个数
{
for (int j = 0; j < len; j++)//遍历数组并入队
{
index = GetNum(arr[j], i);
queArr[index].push(arr[j]);//将数字放入对应的队列
}
//依次出队
int j = 0;
for (int k = 0; k < 10; k++)
{
while (!queArr[k].empty())
{
arr[j++] = queArr[k].front();
queArr[k].pop();
}
}
}
return arr;
}
int maximumGap(vector<int>& nums)
{
if (nums.size() < 2)
return 0;
RadixSort(nums, nums.size());
int max = INT_MIN;
for (int i = 0; i < nums.size() - 1; i++)
{
if (abs(nums[i] - nums[i + 1]) > max)
{
max = abs(nums[i] - nums[i + 1]);
}
}
return max;
}
};
905. 按奇偶排序数组
给定一个非负整数数组 A
,返回一个数组,在该数组中, A
的所有偶数元素之后跟着所有奇数元素。
你可以返回满足此条件的任何数组作为答案。
示例:
输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。
双指针
class Solution
{
public:
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
vector<int> sortArrayByParity(vector<int>& nums)
{
int left = 0;
int right = nums.size() - 1;
while (left < right)
{
while (nums[left] % 2 == 0)
{
if (++left >= nums.size())
break;
}
while (nums[right] % 2 == 1)
{
if (--right < 0)
break;
}
if (left >= nums.size() || right < 0)
break;
if(left<right)
Swap(nums[left], nums[right]);
left++;
right--;
}
return nums;
}
};
539. 最小时间差
给定一个 24 小时制(小时:分钟 “HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
示例 1:
输入:timePoints = [“23:59”,“00:00”]
输出:1
化为分钟+排序
注意点:时间要看做两天来计算
class Solution
{
public:
int findMinDifference(vector<string>& timePoints)
{
vector<int>arr;
int h;
int m;
for (auto n : timePoints)
{
h = 0;
m = 0;
for (int i = 0; i < 5; i++)
{
if (i < 2)
{
h = h * 10 + n[i] - '0';
}
else if (i > 2)
{
m = m * 10 + n[i] - '0';
}
}
arr.push_back(h * 60 + m);
if (h < 12)//也可以不要这个h<12,直接看做两天即可,一天24小时,<12是把前12小时再算一遍
{
arr.push_back((h+24) * 60 + m);
}
}
sort(arr.begin(), arr.end());
int min = INT_MAX;
for (int i = 0; i < arr.size() - 1; i++)
{
if (arr[i] == arr[i + 1])
{
return 0;
}
if (min > abs(arr[i] - arr[i + 1]))
{
min = abs(arr[i] - arr[i + 1]);
}
}
return min;
}
};
976. 三角形的最大周长
给定由一些正数(代表长度)组成的数组 A
,返回由其中三个长度组成的、面积不为零的三角形的最大周长。
如果不能形成任何面积不为零的三角形,返回 0
。
示例 1:
输入:[2,1,2]
输出:5
3个for循环 超时
class Solution
{
public:
int largestPerimeter(vector<int>& nums)
{
int max = INT_MIN;
sort(nums.begin(), nums.end());
for (int i = 0; i <nums.size()-2; i++)
{
for (int j = i + 1; j < nums.size() - 1; j++)
{
for (int k = j + 1; k < nums.size() ; k++)
{
if (nums[i] + nums[j] > nums[k]&&nums[i]+nums[j]+nums[k]>max)
{
max = nums[i] + nums[j] + nums[k];
}
}
}
}
return max == INT_MIN ? 0 : max;
}
};
上述代码改为从后往前遍历
class Solution
{
public:
int largestPerimeter(vector<int>& nums)
{
sort(nums.begin(), nums.end());
for (int i = nums.size() - 1; i >= 2; i--)
{
for (int j = i - 1; j >= 1; j--)
{
for (int k = j - 1; k >= 0; k--)
{
if (nums[j] + nums[k] > nums[i])
{
return nums[i] + nums[j] + nums[k];
}
else
break;
}
}
}
return 0;
}
};
去看了题解
说实话,内心还是有点隐隐的不认同
我们一定是选「小于 c 的最大的两个数」
class Solution
{
public:
int largestPerimeter(vector<int>& nums)
{
sort(nums.begin(), nums.end());
for (int i = nums.size() - 1; i >= 2; i--)
{
if (nums[i] < nums[i - 1] + nums[i - 2])
return nums[i] + nums[i - 1] + nums[i - 2];
}
return 0;
}
};
881. 救生艇
第 i
个人的体重为 people[i]
,每艘船可以承载的最大重量为 limit
。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit
。
返回载到每一个人所需的最小船数。(保证每个人都能被船载)。
示例 1:
输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)
排序
因为最多只能坐两人 且 两人重量之和最多为limit
所以设置left和right,如果未上船的最重+最轻>limit,那么就最重的上船走;否则,两人一起上船
class Solution
{
public:
int numRescueBoats(vector<int>& people, int limit)
{
sort(people.begin(), people.end());
int left = 0;
int right = people.size() - 1;
int num = 0;
while (left <= right)
{
if (people[left] + people[right] > limit)
{
right--;
}
else
{
left++;
right--;
}
num++;
}
return num;
}
};