移动零
思路一
两层循环,第一个指针指向0,第二个指针指向第一个不为0的数,交换两个指针,时间复杂度为O(n2)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int zero, non_zero;
for (zero = 0; zero < nums.size(); zero++) {
//找到第一个0
if (nums[zero] == 0) {
for (int non_zero = zero + 1; non_zero < nums.size(); non_zero++) {
if (nums[non_zero] != 0) {
swap(nums[zero], nums[non_zero]);
break;
}
}
}
}
return;
}
};
思路二
选择用两个指针,快慢指针,开始时都指向第一个0,快指针向后遍历,如果是0则继续,如果不是0则让慢指针赋值为快指针,当快指针遍历完成后,慢指针遍历升序数组,都赋值为0
此时,时间复杂度为O(n)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int fast,slow;
//找到第一个0
for(slow=0;slow<nums.size();slow++){
if(nums[slow]==0)break;
}
//快指针赋值给慢指针
fast=slow+1;
while(fast<nums.size()){
if(nums[fast]==0)fast++;
else {
nums[slow]=nums[fast];
slow++;
fast++;
}
}
//慢指针最后赋值0
while(slow<nums.size()){
nums[slow++]=0;
}
return;
}
};
盛最多的水
思路一(超时)
本题可以使用两层循环,分别遍历左边的高度h1和右边的高度h2,找到最大值(h1和h2与x轴围成的面积),时间复杂度O(n2),但是超时了
class Solution {
public:
int maxArea(vector<int>& height) {
int max = 0;
for (int i = 0; i < height.size(); i++) {
for (int j = i + 1; j < height.size(); j++) {
if ((min(height[i], height[j]) * (j - i)) > max) {
max = min(height[i], height[j]) * (j - i);
}
}
}
return max;
}
};
思路二
指路一个大神解析
- 当前柱子是最两侧的柱子,水的宽度 d 为最大,其他的组合,水的宽度都比这个小。
- 左边柱子较短,决定了水的高度为 3。如果移动左边的柱子,新的水面高度不确定,一定不会超过右边的柱子高度 7。
- 如果移动右边的柱子,新的水面高度一定不会超过左边的柱子高度 3,也就是不会超过现在的水面高度。
因此,选择两个指针,分别指向头尾,得到当前面积,将较小的指针移动,得到新的当前面积,直到两个指针相遇,结束遍历,得到最终最大面积,时间复杂度为O(n)
神之一图:
class Solution {
public:
int maxArea(vector<int>& height) {
int max = 0;
int left = 0, right = height.size()-1;
while (left != right) {
int s;
s=min(height[left],height[right])*(right-left);
if (s > max)max = s;
if (height[left] < height[right])left++;
else right--;
}
return max;
}
};
两数之和Ⅱ
本题和上题可以用类似的方法,指路大神操作
即一次排除多个单元格,选择两个指针,分别指向首位A[0]
,A[n]
,A为升序
- 如果
A[0]+A[n]>target
,说明A[1]+A[n]/A[2]+A[n]…都大于target- 如果
A[0]+A[n]<target
,说明A[0]+A[n-1]/A[0]+A[n-2]…都小于target以上两种情况都可以排除“神之一图”中的一行或一列
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left=0,right=numbers.size()-1;
while(left!=right){
if(numbers[left]+numbers[right]==target){
return {left+1,right+1};
}
if(numbers[left]+numbers[right]<target)left++;
if(numbers[left]+numbers[right]>target)right--;
}
return {left+1,right+1};
}
};