283,移动0
我先前是打算前后两个指针分别遍历如果找到0,就交换,但是效率太低,要多吃判断。
改进方法,创建一个虚拟的数组,同时一次遍历,只需得到非0的元素放入虚拟数组中,再其他都是0,即可
void moveZeroes(int* nums, int numsSize)
{
if (numsSize < 1)
return;
int front = 0;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] != 0)
{
nums[front] = nums[i];
++front;
}
}
while (front < numsSize)
{
nums[front] = 0;
++front;
}
}
这是利用题目的特性。
但是其中虚拟数组的使用是非常好的方法。
26,删除重复项
常规方法,都是遍历一个元素,再向后遍历,如果找到相同的元素,就将后面元素依次向前移动,覆盖,这种效率低,时间复杂度有O(n^2),而最好是一次遍历,就完成。
为减少空间的消耗,就不去开辟新的空间,主要是这方法在力扣里也不好使,分分钟会教你做人。
就不开辟新空间,一次遍历循环结束。
可以使用虚拟数组的方法,假装开辟一个空间,其实是下标的不同,内存还是原空间。
int removeDuplicates(int* nums, int numsSize)
{
int pre = 0;
int new = 0;
nums[new] = nums[pre];
int num = 1;
if (numsSize == 0)
return 0;
for (pre=1; pre < numsSize; pre++)
{
if (nums[new] != nums[pre])
{
new++;
nums[new] = nums[pre];
num++;
}
}
return num;
}
如果原数组中,元素和new中一样就跳过,不一样就赋值new。不用担心不去new数组遍历会导致重复,题目要求,有序数组,如果没要求,也可以自己qsort快排一下。
其实很多数组操作题,最好都排序一下在操作,因为排数之后有可能会有一定规律。
66,加一
这种题目和两数之和
一样,不能通过传统的先算和在分开算各个位数,至少在力扣上不切实际,因为力扣会给一个好大好大的数作为通过案例,任何数据类型都不能表示,所以,我们只能从内存的角度去解决这类问题。
这也是倒序的数组,更要谨慎。题目说了,每个元素都是0到9的数。但题目要求加一。先来看看,如果加一会是什么情况。
1,
{2,3,4}
235=234+1;
输出还是
{2,3,5}
2,{9,9}
100=99+1;
输出却是
{1,0,0}
会改变数组的大小
而我们要对数组操作也只能从后向前操作。
传统方法也可以(如果限定条件的话)
int* plusone(int* digits, int digitssize, int* returnsize)
{
int sum = 0;
for (int i = 0; i < digitssize; i++)
{
sum = sum * 10 + digits[i];
}
sum += 1;
int i = 0;
int num = sum;
while (num)
{
i++;
num /= 10;
}
*returnsize = i;
int* p =(int*)malloc(sizeof(int) * (*returnsize));
i--;
while (sum)
{
p[i] = sum % 10;
sum /= 10;
i--;
}
return p;
}
传统方法。这其实也不错。
但是为了更多的可使用性,要从另一个角度思考问题。将每个元素分开看。
最大就是9,加一也不过是进了一位,对新元素的影响也不过是多了一个一。如果是{9,9,9,9}加一也只是{1,0,0,0,0}。主要是每一位,是不是9.
如果最后一位不是9,就直接加1赋值后就可以直接return了,当是9,时就循环,去前一个元素继续判断。
int* plusOne(int* digits, int digitsSize, int* returnSize)
{
int* p = malloc(sizeof(int) * digitsSize);
int i = digitsSize - 1;
for (; i >=0; i--)
{
digits[i] += 1;
if (digits[i] % 10 != 0)
{
*returnSize = digitsSize;
return digits;
}
digits[i] %= 10;
}
p = (int*)realloc(p,sizeof(int) * (digitsSize + 1));
for (int i = 0; i < digitsSize; i++)
{
p[i + 1] = digits[i];
}
p[0] = 1;
*returnSize = digitsSize + 1;
return p;
}
是不是比传统方法巧妙。如果能出循环说明你每一位都是9,就需要realloc新的空间,首元素也就只能是1.在把原数组的元素copy到新的空间来。
巧妙。