二、数组2(基础算法思路的应用与对撞指针)
基础算法思路的应用
75. 颜色分类
- 解法一
计算每个颜色的个数,然后填充数组
class Solution {
public:
void sortColors(vector<int>& nums) {
int count[3] = {0};
for(int i=0; i<nums.size(); ++i){
assert(nums[i]>=0 && nums[i]<=2);
++count[nums[i]];
}
int index=0;
// for(int i=0; i<count[0]; ++i){
// nums[index] = 0;
// ++index;
// }
// for(int i=0; i<count[1]; ++i){
// nums[index] = 1;
// ++index;
// }
// for(int i=0; i<count[2]; ++i){
// nums[index] = 2;
// ++index;
// }
for(int i=0; i<3; ++i){
for(int j=0; j<count[i]; ++j){
nums[index] = i;
++index;
}
}
}
};
- 解法2
利用三路快排
class Solution {
public:
void sortColors(vector<int>& nums) {
// 采用三路快排的思想进行排序
int v = 1;
// <v [l, lt]
// ==v [lt+1, i)
// >v [gt, r]
int lt=-1;
int gt=nums.size();
int i=0;
while(i<gt){
if(nums[i]<v){
swap(nums[lt+1], nums[i]);
++lt;
++i;
}
else if(nums[i]>v){
swap(nums[gt-1], nums[i]);
--gt;
}
else{ // nums[i] == v
++i;
}
}
}
};
88. 合并两个有序数组
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
// 开辟一个辅助数组 复制nums1 然后再将辅助数组和nums2合并到nums1
vector<int> aux(nums1.begin(), nums1.begin()+m);
int j=0; // aux
int k=0; // nums2
for(int i=0; i<nums1.size(); ++i){
if(j>=m){
nums1[i] = nums2[k];
++k;
}
else if(k>=n){
nums1[i] = aux[j];
++j;
}
else if(aux[j]<nums2[k]){
nums1[i]=aux[j];
++j;
}
else if(aux[j]==nums2[k]){
nums1[i] = aux[j];
++i;
nums1[i] = nums2[k];
++j;
++k;
}
else{ // aux[j]>nums2[k]
nums1[i] = nums2[k];
++k;
}
}
}
};
215. 寻找第K大的元素
利用双路快排解法
class Solution {
public:
int __partition(vector<int>& nums, int l, int r){
swap(nums[l], nums[rand()%(r-l+1)+l]);
int v = nums[l];
// <v [l+1, i)
// >v (j, r]
int j=r;
int i=l+1;
while(true){
while(i<=r && nums[i]<v)
++i;
while(j>=l+1 && nums[j]>v)
--j;
if(i>j)
break;
swap(nums[i], nums[j]);
++i;
--j;
}
swap(nums[l], nums[j]);
return j;
}
int __findKthLargest(vector<int>& nums, int l, int r, int k){
// 利用双路快排进行寻找第k大元素
if(l>r)
return 0;
int p=__partition(nums, l, r);
if(p==nums.size()-k){
return p;
}
else if(p<nums.size()-k)
return __findKthLargest(nums, p+1, r, k);
else // p>nums.size()-k
return __findKthLargest(nums, l, p-1, k);
}
int findKthLargest(vector<int>& nums, int k) {
srand(time(NULL));
return nums[__findKthLargest(nums, 0, nums.size()-1, k)];
}
};
对撞指针
167. 两数之和II-输入有序数组
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
// 对撞指针
int l=0;
int r=numbers.size()-1;
while(l<r){
if(numbers[l]+numbers[r]==target){
int res[2] = {l+1, r+1};
return vector<int>(res, res+2);
}
else if(numbers[l]+numbers[r]<target){
++l;
}
else{
--r;
}
}
return {};
}
};
125. 验证回文串
class Solution {
public:
bool isPalindrome(string s) {
int j=0;
for(int i=0;i<s.size(); ++i){
if(s[i]>=65&&s[i]<=90){
s[j] = s[i];
++j;
}
else if(s[i]>=97&&s[i]<=122){
s[j] = s[i] - 32;
++j;
}
else if(s[i]>=48&&s[i]<=57){
s[j] = s[i];
++j;
}
}
// 对撞指针
int l=0;
int r=j-1;
while(l<r){
if(s[l] == s[r]){
++l;
--r;
}
else
return false;
}
return true;
}
};
344. 反转字符串
class Solution {
public:
void reverseString(vector<char>& s) {
int l=0;
int r=s.size()-1;
while(l<r){
swap(s[l], s[r]);
++l;
--r;
}
}
};
11. 盛最多水的容器
暴力解法超时
巧妙的双指针解法
class Solution {
public:
int maxArea(vector<int>& height) {
// 双指针 从两端遍历
// 由于从两端往中间移动,底总是变小的
// 因此,总是要保证找到比较高的位置
// 因此左边矮,就把左边往右移,右边同理
// 理解:一个高的一个矮的进行计算面积,隐含着从矮的到高的这个区间所有的当前矮墙与其它墙的组合已经不成立
// 因而计算完当前组合后,就可以丢弃矮墙,进行剩下的组合计算
int l = 0;
int r = height.size()-1;
int max_area = 0;
while(l<r){
max_area = max(max_area, (r-l)*min(height[l], height[r]));
if(height[l]>height[r])
--r;
else
++l;
}
return max_area;
}
};