方法一:双指针。右指针一直往后移动。当右指针遇到0时,左指针停下。当右指针不为0时,交换两个指针对应位置的值。理由:左指针停下的位置一定是0,右指针不为0时交换,就保证了把非零数换到了前面。
代码如下:
class Solution
{
public:
void moveZeroes(vector<int>& nums)
{
int n = nums.size();
int left = 0, right = 0;
while (right < n)
{
if (nums[right])
{
swap(nums[left], nums[right]);
left++;
}
right++;
}
}
};
方法二:依然是双指针,但思路不同。思路:遇到非零数就往前放。放完非零数后往数组后面补0即可。
class Solution
{
public:
void moveZeroes(vector<int>& nums)
{
int left = 0, right = 0;
int n = nums.size();
while (right < n)
{
if (nums[right])
{
nums[left++] = nums[right];
}
right++;
}
for (int i = left; i < n; i++)
{
nums[i] = 0;
}
}
};
第二题:11. 盛最多水的容器 - 力扣(LeetCode)
方法:贪心+双指针。左指针从最左端开始,右指针从最右端开始。面积=宽*左右指针对应高度较小的那一个。因此哪个指针对应高度较小,就要移动,这样才有可能遇到更高的高度。
class Solution
{
public:
int maxArea(vector<int>& height)
{
int n = height.size();
int left = 0, right = n - 1;
int ans = (right - left) * min(height[left], height[right]);
while (left < right)
{
if (height[left] < height[right]) left++;
else right--;
ans = max(ans, (right - left) * min(height[left], height[right]));
}
return ans;
}
};
方法:双指针。先排序,这样好找。假设三个数对应的位置为first,second,third.那么目标值=-nums[first].右指针从末尾往前,左指针从first+1往后即可。
这题需要注意去重。之所以是nums[first]==nums[first-1],是因为nums[first-1]一定已经被处理过了。second那里同理。
class Solution
{
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>>ans;
int n = nums.size();
sort(nums.begin(), nums.end());
if (nums[0] == 0 && nums[n - 1] > 0)
{
return {};
}
else if (nums[0] == 0 && nums[n - 1] == 0)
{
return { {0,0,0} };
}
for (int first = 0; first < n - 2; first++)
{
//去重a
if (first > 0 && nums[first] == nums[first - 1]) continue;
int target = -nums[first];
int third = n - 1;
for (int second = first + 1; second < n - 1; second++)
{
//去重b
if (second > first + 1 && nums[second] == nums[second - 1]) continue;
while (second<third && nums[second] + nums[third]>target) third--;
if (second == third) break;//对于a来说找不到b+c+=-a,first指针后移
if (nums[second] + nums[third] == target)
{
ans.push_back({ nums[first],nums[second],nums[third] });
}
}
}
return ans;
}
};
方法:dp。这题也可以使用双指针,但是dp更好理解,不过空间复杂度是O(n),双指针是O(1)。
对于下标i,它所能装的水的高度=它左边最高柱子高度与它右边最高柱子高度当中较小的那一个。所以对于每个下标i,我们只需要统计出其左边最高柱子高度和右边最高柱子高度。直接枚举的话复杂度为O(n^2),采用动态规划更好。对于下标i,其左边最高柱子要么是i-1左边最高柱子,要么是它自己本身,右侧同理。
class Solution
{
public:
int trap(vector<int>& height)
{
int n = height.size();
vector<int>left_max(n);
vector<int>right_max(n);
left_max[0] = height[0], right_max[n - 1] = height[n - 1];
for (int i = 1; i < n; i++)
{
left_max[i] = max(left_max[i - 1], height[i]);
}
for (int i = n - 2; i >= 0; i--)
{
right_max[i] = max(right_max[i + 1], height[i]);
}
int ans = 0;
for (int i = 0; i < n; i++)
{
ans += min(left_max[i], right_max[i]) - height[i];
}
return ans;
}
};
和单调栈差不多。