目录
第一题,移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int dest=-1;
for(int cur=0;cur<nums.size();cur++)
{
if(nums[cur]!=0){
swap(nums[++dest],nums[cur]);
}
}
}
};
第二题,复写零
给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
解析:
从前往后进行复写会导致原来的数据被覆盖掉,所以我们考虑先找到最后一个复写的数据从后面往前面开始复写
但是在找最后一个复写的数据的时候若最后一个复写数据为0,那么dest指针可能会越界
while(dest<arr.size()){//这样写找的cur是超出的那个数据,需要额外判断情况太麻烦
if(arr[cur]=0){
cur++;
dest+=2;//步长为2就可能越界
}
else{
++cur;
++dest
}
}
public:
void duplicateZeros(vector<int>& arr) {
int cur=0,dest=-1,n=arr.size();//我不知道dest的最后位置是什么,需要进行模拟所以初始化为-1
while(cur<n){
if(arr[cur]==0){
dest+=2;
}
else{
dest++;
}
if(dest>=n-1) break;//先判断写入的是否越界,若不越界才继续向下找
cur++;
}
if(dest==n){
arr[n-1]=0;
dest-=2;
cur--;
}
while(cur>=0){
if(arr[cur]==0){
arr[dest--]=0;
arr[dest--]=0;
cur--;
}
else{
arr[dest--]=arr[cur--];
}
}
}
};
第三题 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程结果为 1,那么这个数就是快乐数。
一个数经过这个操作以后一定会缩小取值范围,由鸽巢原理可知总是会陷入循环。
class Solution {
public:
bool isHappy(int n) {
int slow=n,fast=n;
fast=0;
while(n!=0){
fast+=(n%10)*(n%10);
n/=10;
}
while(slow!=fast){
int tmp1=slow;
int tmp2=fast;
slow=fast=0;
while(tmp1!=0){
slow+=(tmp1%10)*(tmp1%10);
tmp1/=10;
}
while(tmp2!=0){
fast+=(tmp2%10)*(tmp2%10);
tmp2/=10;
}
tmp2=fast;
fast=0;
while(tmp2!=0){
fast+=(tmp2%10)*(tmp2%10);
tmp2/=10;
}
}
if(slow==1){
return true;
}
return false;
}
};
当然我们可以观察到取每一位数的平方和多次使用,所以我们可以封装一个函数
class Solution {
public:
int all_sum(int n){
int sum=0;
while(n!=0){
sum+=(n%10)*(n%10);
n/=10;
}
return sum;
}
bool isHappy(int n) {
int slow=n,fast=all_sum(n);
while(slow!=fast){
slow=all_sum(slow);
fast=all_sum(all_sum(fast));
}
if(slow==1)
return true;
return false;
}
};
第四题 盛最多容器的水
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/container-with-most-water
我们可以知道选小的那个杯壁向内枚举,无论如何只会使得我们的体积变小
class Solution {
public:
int maxArea(vector<int>& height) {
int ret=0;
int left=0,right=height.size()-1;
while(left<right){
int min_high=height[left];
if(height[left]>height[right]){
min_high=height[right];
}
int tmp=min_high*(right-left);
if(tmp>ret){
ret=tmp;
}
if(height[left]>height[right]){
right--;
}
else{
left++;
}
}
return ret;
}
};
更简洁的写法
int ret=0;
int left=0,right=height.size()-1;
while(left<right){
int tmp=min(height[left],height[right])*(right-left);
ret=max(tmp,ret);
if(height[left]<height[right]) left++;
else right--;
}
return ret;
第五题.有效三角形个数
给定一个包含非负整数的数组 nums
,返回其中可以组成三角形三条边的三元组个数。
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int ret=0,left=0,right=0;
for(int i=nums.size()-1;i>=2;i--){
left=0,right=i-1;
while(left<right){
if(nums[right]+nums[left]>nums[i]){
ret=ret+right-left;
right--;
}
else{
left++;
}
}
}
return ret;
}
};
第六题 两数之和
题主错解
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret;
ret.resize(2);
sort(nums.begin(),nums.end());//排序以后你就不知道他原来的下标是多少了
int left=0,right=nums.size()-1;
while(left<right){
if(nums[left]+nums[right]>target){
right--;
}
else if(nums[left]+nums[right]<target){
++left;
}
else if(nums[left]+nums[right]==target){
ret[0]=left;
ret[1]=right;
break;
}
}
return ret;
}
};
利用哈希表快速查找不失为一种好方法
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end()) {
return {it->second, i};
}
hashtable[nums[i]] = i;
}
return {};
}
};
第七题 三数之和
在给定的代码中,存在一个潜在的越界问题。当left
和right
指针移动时,对tmp
的更新没有放在循环的内部,导致在检查tmp
是否大于、小于或等于sum
时,使用的是旧值,而不是更新后的值。
这会导致在某些情况下,left
和right
指针无法正确地移动,从而导致越界访问。
为了修复这个问题,你应该将更新tmp
的语句放置在while
循环内部,确保它在每次循环迭代时都能够更新到正确的值。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
int n=nums.size();
int target=0;
sort(nums.begin(),nums.end());
for(int i=0;i<n;){
int a=nums[i];
int sum=target-a;
int left=i+1,right=n-1;
int tmp=nums[left]+nums[right];
while(left<right){
if(tmp>sum){
right--;
}
else if(tmp<sum){
left++;
}
else{
ret.push_back({nums[i],nums[left],nums[right]});
left++;//为下一轮和本轮去准备
right--;
while(left<right&&nums[left]==nums[left-1]){//去重
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
}
}
i++;//思考一下这里为什么要i++
while(i<n&&nums[i]==nums[i-1]){
i++;
}
}
return ret;
}
};
此外还需要注意 右指针去重时应该向左移动指针
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
int n=nums.size();
int target=0;
sort(nums.begin(),nums.end());
for(int i=0;i<n;){
int a=nums[i];
int target=0;
int left=i+1,right=n-1;
while(left<right){
int sum=nums[left]+nums[right];
if(sum+a>target){
right--;
}
else if(sum+a<target){
left++;
}
else{
ret.push_back({nums[i],nums[left],nums[right]});
left++;//为下一轮和本轮去准备
right--;
while(left<right&&nums[left]==nums[left-1]){//去重
left++;
}
while(left<right&&nums[right]==nums[right+1]){//此处应该是+1,属于双指针问题
right--;
}
}
}
i++;//思考一下这里为什么要i++
while(i<n&&nums[i]==nums[i-1]){
i++;
}
}
return ret;
}
};