1.移动零
class Solution {
public:
void moveZeroes(vector<int>& nums) {
//数组划分问题,采取双指针方法
//定义cur来遍历数组,定义dest来指向非零元素的最后一个位置
//数组划分为[0,dest]为非零元素,[dest+1,cur-1]为0元素,[cur,nums.size()-1]为未处理区间
//直到cur遍历完数组
for(int cur=0,dest=-1;cur<nums.size();cur++)
{
//dest初始化为-1,非零元素区间一开始为0,随着cur遍历数组遇到非零值,我们增加区间大小。
//由于我们dest是指向非零元素的最后一个位置,因此新增区间的元素为0,我们与非零值交换
if(nums[cur])
{
swap(nums[++dest],nums[cur]);
}
}
}
};
2.复写零
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
//采用双指针方法,定义cur指向要复写的元素,定义dest指向复写的位置
//复写应从右到左否则会覆盖元素
//1.找出最后一个复写的元素
//2.进行复写
int cur=0,dest=-1,n=arr.size();
//一定要将arr.size()赋值给n再用n去比较,如果用arr.size()与dest进行比较,隐式类型转换会把dest变成unsigned int的最大值
//开始处未进行复写,因此我们定义dest
//建议通过cur来控制循环而不是dest
//判断条件不是很直观
while (dest < n-1)
{
if (arr[cur])
{
dest++;
}
else
{
dest += 2;
}
if(dest<=n-2)
cur++;
}
/*while(cur < n)
{
if(arr[cur]) dest++;
else dest += 2;
if(dest >= n - 1) break;
cur++;
}*/
//循环结束后,我们发现cur正好指向最后一个需要复写的元素,而dest正好指向下标为n-1处或下标为n处,
//注意特殊情况,当最后一个cur为0,dest需要复写两次要但此时数组的只剩下一个单位的空间,此时需要特殊处理
if(dest==n)
{
arr[n-1]=0;
dest-=2;
cur--;
}
while(dest>=0)
{
if(arr[cur])
{
arr[dest]=arr[cur];
}
else
{
arr[dest]=0;
arr[--dest]=0;
}
cur--;
dest--;
}
}
};
3.快乐数
class Solution {
public:
int bit_sum(int n)
{
int ret=0;
while(n)
{
int bit=n%10;
ret+=bit*bit;
n/=10;
}
return ret;
}
bool isHappy(int n) {
//根据鸽巢原理,简单来说就是十一只鸽子飞进是个鸟笼,至少有一个鸟笼的鸽子是大于等于1的
//对于一个n位数来说,他的每个位置上的数字的平方和最大为81*n,区间为[1,81*n]
//任何一个n位数经过最多81*n次变换一定会有重复的数字
//而快乐数特指在1循环,而其他数可能循环的区间有多个数
//遇到循环我们很轻易的想到快慢指针的方法
int slow=n,fast=bit_sum(n);
while(slow!=fast)
{
slow=bit_sum(slow);
fast=bit_sum(bit_sum(fast));
}
return slow==1;
}
};
4.盛水最多的容器
class Solution {
public:
int maxArea(vector<int>& height) {
//容纳最多的水意味着容器的面积要最大
//定义h为两端中较矮的一侧(否则水会流出来),定义w(宽)为右端下标-左端小标
//可以得到V=h*w
//对最左边到最右边这个区间来说他的w是最大的,向内收拢的过程中w一定会减小,因此我们希望h能增大以便让总面积增大
//只有较矮一侧的高度增加才有可能让总面积变大,因此我们使用双指针遍历数组
int left =0,right=height.size()-1;
int h=height[left]>height[right]?height[right]:height[left];
int max=h*(right-left);
//不要用等号会越界,如[1,1],right会走到-1。如果调整一下求和顺序就可以
while(left<right)
{
if(height[left]<height[right])
left++;
else
right--;
h=height[left]>height[right]?height[right]:height[left];
int ret=h*(right-left);
max=max>ret?max:ret;
}
return max;
}
};
class Solution {
public:
int maxArea(vector<int>& height) {
int left = 0, right = height.size() - 1, ret = 0;
while (left <= right) {
int v = min(height[left], height[right]) * (right - left);
ret = max(ret, v);
// 移动指针
if (height[left] < height[right])
left++;
else
right--;
}
return ret;
}
};
5.有效三角形个数
class Solution {
public:
int triangleNumber(vector<int>& nums) {
//三角形的最小两边之和大于第三边
//对数组进行排序(升序)
//固定一个最大边(子数组的最右边),倘若子数组的最左边和最数组的最右边的前一个元素之和大于第三边
//则子数组中剩余的元素+最右边的前一个元素之和也都大于第三边,总元素个数为right-left
//采用双指针
sort(nums.begin(),nums.end());
int count=0;
//三元组的结束应该是最大值下标为[2]处
for(int i=nums.size()-1;i>=2;i--)
{
int left=0,right=i-1;
while(left<right)
{
if(nums[left]+nums[right]>nums[i])
{
count+=right-left;
right--;
}
else
left++;
}
}
return count;
}
};