001 移动零
1 题目描述
2 思路
3 代码
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int dest = -1;
int cur = 0;
int n = nums.size();
while(cur <= n-1)
{
if(nums[cur] != 0)
{
++dest;
swap(nums[dest], nums[cur]);
}
++cur;
}
}
};
002 复写零
1 题目描述
2 思路
3 代码
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
//正向双指针,找最后一个“复写”的数
int cur = 0;
int dest = -1;
int n = arr.size();
while(cur < n)
{
if(arr[cur] != 0)
{
++dest;
}
else
{
dest += 2;
}
if(dest >= n -1) break;
++cur;
}
//2、处理特殊情况:dest超出arr的上界
if(dest > n - 1)
{
arr[n-1] = 0;
//更新边界
dest-=2;
--cur;
}
//反向从后往前进行复写,此时cur->最后一个复写数,dest->arr中最后一个元素
while(cur >= 0)
{
//arr[cur] != 0,不需要复写0
if(arr[cur] != 0)
{
arr[dest] = arr[cur];
--dest;
}
else//arr[cur] == 0
{
//arr[cur] == 0,需要复写0(arr[cur])
arr[dest] = arr[cur];
arr[dest - 1] = arr[cur];
dest -= 2;
}
--cur;
}
}
};
003 快乐数(有环问题)
1 题目描述
2 思路
3 代码
class Solution {
public:
//返回num这个数每一位的平方和sum
int computeNum(int num)
{
int sum = 0;
while(num != 0)
{
int result = num % 10;
sum = result*result + sum;
num = num/10;
}
return sum;
}
明确:如果是快乐树,则它们在环中相遇时快慢指针指向的数肯定为1
如果不是快乐数,则它们在环中相遇时快慢指针指向的数肯定不为1
bool isHappy(int n)
{
//slow指向第一个数,fast指向第二个数
int slow = n;
int fast = computeNum(n);
fast = computeNum(fast);
while(fast != slow)
{
fast = computeNum(fast);
fast = computeNum(fast);
slow = computeNum(slow);
}
if(slow == 1)
return true;
else
return false;
}
};
004 盛最多容器的水
题目描述
2 思路
3 代码
class Solution {
public:
int maxArea(vector<int>& height)
{
int maxArea = -1;
int n = height.size();
int left = 0;
int right = n - 1;
while(left < right)
{
int computeArea = min(height[left], height[right]) * (right - left);
//数组中其他数与height[left]所组成的体积肯定比computeArea小,不用计算,++left
if(height[left] < height[right])
{
++left;
}
else //height[left] >= height[right]
{
--right;
}
maxArea = max(maxArea, computeArea);
}
return maxArea;
}
};
005 有效三角形的个数
1 题目描述
2 思路
3 代码块
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int n = nums.size();
int k = 0; //用于统计有效三角形个数
for(int i = n-1 ; i >= 2; --i)
{
int left = 0;
int right = i - 1;
while(left != right)
{
if(nums[left] + nums[right] > nums[i])
{
//此时[left, right]之间的数与nums[right]和nums[i]所组成的三角片均为合法三角形
k = k + (right - left);
--right;
}
else
{
++left;
}
}
}
return k;
}
};
006 两数之和
1 题目描述
2 思路
3 代码
class Solution {
public:
vector<int> twoSum(vector<int>& price, int target) {
int left = 0;
int right = price.size() - 1;
vector<int> res;
//排序 + 双指针解决
while(left != right)
{
//由于是升序,如果左右指针指向的数,比目标数要大
//故要想等于target,则需right--,然后继续判断
if(price[left] + price[right] > target)
{
--right;
}
else if(price[left] + price[right] < target)
{
//由于是升序,如果左右指针指向的数,比目标数要小
//故要想等于target,则需left--,然后继续判断
++left;
}
else
{
//由左右指针指向的数等于target,
//保存两数,退出循环。
res.push_back(price[left]);
res.push_back(price[right]);
break;
}
}
return res;
}
};
007 三数之和
1 题目描述
2 思路
3 代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> ret;
//1、排序
sort(nums.begin(),nums.end());
//利用双指针解决问题
int n = nums.size();
//其实这里最合理的是i < n-1, 等于n -1 时不用判断了,因为left与right指向同一个数,而题目要求三数要不同
//这里i < n 也没有问题,后续会处理i = n - 1的情况。
for(int i = 0; i < n; ) //遍历固定数
{
//小优化,如果我们固定数nums[i] > 0,由于这为一个升序的的vector
//故在固定数后续区间[left, right]区间内肯定找不到两个数的和等于nums[i]
if(nums[i] > 0) break;
int left = i + 1;
int right = n - 1;
int target = -nums[i];
while(left < right)
{
int sum = nums[left] + nums[right];
if(sum > target)
{
--right;
}
else if(sum < target)
{
++left;
}
else
{
//如果相等sum = target,则说明left与right指针所指向的数满足三元组的要求
ret.push_back({nums[i], nums[left], nums[right]});
++left;
--right;
//去重,以及防止去重的过程中发生left、right发生越界
while(left < right && nums[left] == nums[left - 1]) ++left;
while(right > left && nums[right] == nums[right + 1]) --right;
}
}
//去重i
++i; //下一个固定数
while(i < n && nums[i] == nums[i - 1])
{
++i;
}
}
return ret;
}
};
008 四数之和
1 题目描述
2 思路
3 代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ret;
//1、排序
sort(nums.begin(), nums.end());
//2、依次固定两个数,双指针解决问题O(n^3)
int n = nums.size();
for(int i = 0; i < n - 3;) // 固定第一个数
{
for(int j = i + 1; j < n - 2; ) //固定第二个数
{
//利用双指针解决问题
int left = j + 1;
int right = n - 1;
long long k = (long long)target - nums[i] - nums[j]; //如果k为int类型,可能会发生数据溢出
while(left < right)
{
int sum = nums[left] + nums[right];
if(sum < k) ++left;
else if(sum > k) --right;
else
{
//当sum和target值相等时,说明找到了符合要求的四数之和,
//继续判断
ret.push_back({nums[i], nums[j], nums[left], nums[right]});
++left;
--right;
//去重,以及避免left,right越界
while(left < right && nums[left] == nums[left - 1]) ++left;
while(right > left && nums[right] == nums[right + 1]) --right;
}
}
//去重j,以及避免j越界
++j;
while(j < n - 2 && nums[j] == nums[j - 1]) ++j;
}
//去重i,以及避免i越界
++i;
while(i < n -3 && nums[i] == nums[i - 1]) ++i;
}
return ret;
}
};