C语言刷题(三)——LeetCode数组篇(初级)

本文详细介绍了LeetCode中关于数组操作的三道经典问题,包括移动零、移除元素和删除重复元素。通过原地操作,实现空间复杂度为O(1)的解决方案。对比了不同算法的效率和实现方式,强调了在有限空间内优化数组结构的重要性。
摘要由CSDN通过智能技术生成

LeetCode——数组篇(初级)

1.给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

输入: nums = [0,1,0,3,12]

输出: [1,3,12,0,0]

解题思路:通过交换第一个0跟第一个非0的元素的位置达到把非零的往前移动。

[0,1,0,3,12] --> 出现0,且1不为0,所以将1跟0换,从而[1,0,0,3,12],往后,再找到3跟第一个0交换,再往后找到12跟3后面的0换从而得到[1,3,12,0,0]

void moveZeroes(int* nums, int numsSize)
{
	int count = 0;
	for (int i = 0; i < numsSize - 1; i++)
	{
		if (nums[i] == 0 && nums[i + 1] == 0)
		{
			count++;
		}else if (nums[i] == 0 && nums[i+1] != 0) {
				int temp = nums[i - count];
				nums[i - count] = nums[i + 1];
				nums[i + 1] = temp;
		}
	}

}

运行结果: 

2.给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素.

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

思路:跟题1的解题思路一样,将val值设置为0即可;

int removeElement(int* nums, int numsSize, int val){
    
	int count = 0;
    int c = 0;
for (int i = 0; i < numsSize; i++)
	{
		if (nums[i] == val)
		{
			nums[i] = 0;
			count++;
		}
	}
	for (int i = 0; i < numsSize - 1; i++)
	{
		if (nums[i] == 0 && nums[i + 1] == 0)
		{
			c++;
		}
		else if (nums[i] == 0 && nums[i + 1] != 0) {
			int temp = nums[i - c];
			nums[i - c] = nums[i + 1];
			nums[i + 1] = temp;
		}
	}

	return numsSize - count;
}

运行结果: 

思路二:设置一个计数器,从0到numsSize。如果nums[i]的值为val,则将当前的与最后一个交换,然后将最后一个元素删除;否则i++;最后返回numsSize。

int removeElement(int* nums, int numsSize, int val){
    
int i = 0;
while (i < numsSize)
{
	/*当我们遇到 nums[i]==val 时,我们可以将当前元素与最后一个元素进行交换,并释放最后一个元素。这实际上使数组的大小减少了 1.*/
	if (nums[i] == val)
	{
		nums[i] = nums[numsSize - 1];
		numsSize--;//数组大小-1
	}
	else
	{
		i++;
	}
}
return numsSize;
}

 运行结果:

总结:第二种算法只需要遍历一次就可以得出结果,而第一种需要遍历一次将其设置为0,在遍历第二次进行排序,从而第二种方法在时间上效率更高;而两种所用的空间都差不多,因此第二种算法更加简洁跟有效率。

 3.给你一个升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]

解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

思路:通过判断相同元素则往后排,通过第一次遍历将相同元素的设置为10001(题中提示最高数为10000),然后对其进行排序,从而是的重复的数往后排比较拖拉一点,因为循环多所以消耗的时间相对比较多。

int removeDuplicates(int* nums, int numsSize)
{
	int len = numsSize;
	int k = 0;
	int j = 0;
	for (k = 0; k < numsSize; k++)
	{
		for (j = k + 1; j < numsSize; j++)
		{
			if (nums[k] == nums[j])
			{
				nums[k] = 10001;
				len--;
			}
		}
	}
	int count = 0;
	for (int i = 0; i < numsSize - 1; i++)
	{
		if (nums[i] == 10001 && nums[i + 1] == 10001)
		{
			count++;
		}
		else if (nums[i] == 10001 && nums[i + 1] != 10001) {
			int temp = nums[i - count];
			nums[i - count] = nums[i + 1];
			nums[i + 1] = temp;
		}
	}
	
	return len;
}

运行结果:

 思路二:通过另一个变量指向第一个,然后判断往后的是否与其相等,如果相等就跳过,不等就将其放到j后面;

int removeDuplicates(int* nums, int numsSize) {
	int i, j = 0;
	for (i = 0; i < numsSize; i++)
	{
		if (nums[i] != nums[j])
		{
			j++;
			nums[j] = nums[i];
		}
	}
	if (numsSize > 0) return j + 1;
	return j;
}

 总结:第一种是排零的思路进行的,将重复的进行设置为阈值外,从而在经过一次排序就可以得到结果。第二种则是通过一次遍历,将重复的删除掉。从而第二种的效率会更高一点。

4.给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。

思路:通过len作为一个不动的元素,将i位置的元素给到len位置的元素,并往后移动一个,而判断条件则是如果有两个相同的,第三个不同,则进行一下赋值,不然len则不变。

int removeDuplicates(int* nums, int numsSize){
int len = 0;
	for (int i = 0; i < numsSize; i++)
	{
		if (len < 2 || nums[len - 2] != nums[i])
		{
			nums[len++] = nums[i];
		}
	}
	return len;
}

运行结果:

 以上都是LeetCode数组类算法的初始定义题目以及解法,个人能力有限,解法上还是很生涩,只供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值