[算法] leetcode顺序表相关题目详解

Posted 哦哦呵呵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[算法] leetcode顺序表相关题目详解相关的知识,希望对你有一定的参考价值。

1. leetcode 203.移除数组元素

/*203. 移除数组元素
* 
示例 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],也会被视作正确答案。

示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

https://leetcode-cn.com/problems/remove-element/

该题分三种思路

解法一

  数组中元素多少是固定的,可以通过遍历数组的方法,将数组遍历一编,将满足条件的元素继续放入数组中,不满足条件的元素不放入数组,最后返回数组与数组大小。

// 遍历数组,将不用删除的元素放入数组
int removeElement1(int* nums, int numsSize, int val) {
    int j = 0;
    for (int i = 0; i < numsSize; i++)
    {
        if (nums[i] != val)
        {
            nums[j++] = nums[i];
        }
    }
    return j;
}

解法二

  使用计数器记录待删除元素出现次数,判断当前元素是否为待删除元素,如果是,则计数器自增1,如果不是,将该元素向前搬移计数器大小步,,计数器大小代表了当前元素应向数组的什么位置存放数据

// 使用计数器记录元素出现个数,如果当前值不是删除的元素则将该元素向前移动count步
int removeElement2(int* nums, int numsSize, int val)
{
    int count = 0;

    for (int i = 0; i < numsSize; i++)
    {
        if (val == nums[i])
            count++;
        else
            nums[i - count] = nums[i];
    }

    return numsSize - count;
}

2. leetcode 26. 删除有序数组中的重复项

* 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
 
示例 1:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
* https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/

解法

  原地搬移数组中元素,因为数组为有序数组,则使用两个指针,两个指针都指向数组头,一个指针用来表示已存放数据的多少,一个指针用来表示当前遍历到数组的第几位。通过两个指针进行判断。
  第一步,将数组第一位直接放入数组,第二步,判断待加入数组与以放入数组的元素是否相同,相同则跳过。

// 因为数组有序,则将第一项加入数组,判断新加入项是否等于已构造好的数组最后一项,相同则不加入
int removeDuplicates(int* nums, int numsSize) 
{
	// 如果长度为1 则数组不重复
	if (numsSize < 2)
		return numsSize;

	int count = 0;

	//nums[count++] = nums[0];
	for (int i = 1; i < numsSize; i++)
	{
		if (nums[count] != nums[i])
			nums[++count] = nums[i];
	}

	return ++count;
}

3. leetcode88. 合并两个有序数组

 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。

示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1] 

提示:
	nums1.length == m + n
	nums2.length == n
	0 <= m, n <= 200
	1 <= m + n <= 200
	-109 <= nums1[i], nums2[i] <= 109

* https://leetcode-cn.com/problems/merge-sorted-array/

解法一

  根据题目要求,要将所有数据放入num1数组中,所以使用双指针来进行计算。
  两个指针分别遍历两个数组,其中比较两个下标位置元素值大小,哪个元素小,就将哪个元素放入数组。直到遍历完一个数组,最后将没有遍历完的数组元素一次放入num1中。
  该方法需要新开辟一个数组空间,空间复杂度较高。

// 1. 使用两个下标,分别遍历两个数组,哪个下标的元素小,就将哪个小标元素放入数组\\
// 需要辅助空间,不然在比较时会导致错误的数据读取
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{
	int pnums1 = 0;
	int pnums2 = 0;
	int count = 0;
	int* arr = (int*)malloc(sizeof(int) * (m + n));

	// 逐个比较,将较大值放入数组
	while (pnums1 < m && pnums2 < n)
	{
		if (nums1[pnums1] >= nums2[pnums2])
		{
			arr[count++] = nums2[pnums2++];
		}
		else
		{
			arr[count++] = nums1[pnums1++];
		}
	}

	// 判断两个数组中哪个没有完成数据的转移,将剩余数据进行转移
	while (pnums1 < m)
		arr[count++] = nums1[pnums1++];
	while(pnums2 < n)
		arr[count++] = nums2[pnums2++];

	nums1 = arr;
}

解法二(推荐)

  该方法与上述方法大致相同,但是不用开辟新的空间。
  因为nums1中的空间已经足够存储,所以从两个数组的最后开始遍历,将较大元素放入,num1中的最后一个位置。

// 2.同样使用两个下标,第一个下标指向第一个数组的最后一个元素的位置,第二个下标指向第二个数字中最后一个元素的位置
// 使用一个指针指向最后一个空间的位置,将两个下标指向的元素最大值放到,空间最后一个位置处
void merge2(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
	int end = m + n - 1;
	int i = m - 1;
	int j = n - 1;

	// nums1 数组长度较长,所以数据会存储在该数组中,存储时数据有序,所以在比对完nums2时,nums1有可能没有比对到头的位置
	// 要保证nums2全部插入到nums1中,nusm1中本身按照顺序存有数据,所以nums1 没有比对到头也不影响结果
	while (j >= 0)
	{
		if (i >= 0 && nums1[i] > nums2[j])
		{
			nums1[end--] = nums1[i--];
		}
		else
		{
			nums1[end--] = nums2[j--];
		}
	}
}

4. 189. 旋转数组

189. 旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1: [7,1,2,3,4,5,6]
向右旋转 2: [6,7,1,2,3,4,5]
向右旋转 3: [5,6,7,1,2,3,4]

示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右旋转 1: [99,-1,-100,3]
向右旋转 2: [3,99,-1,-100]

* https://leetcode-cn.com/problems/rotate-array/

解法一

  可以将旋转个数的元素,进行存储,最后对原数组内容进行移动,最后将旋转的元素存入数组中

解法二

采用先局部逆置,后整体逆置的思想进行解决
在这里插入图片描述

void reverse(int* nums, int start, int end)
{
	while (start < end)
	{
		int num = nums[start];
		nums[start] = nums[end];
		nums[end] = num;
		start++;
		end--;
	}
}

// 先局部逆置元素,最后整体逆置数组元素,即可达到旋转效果
void rotate(int* nums, int numsSize, int k) 
{
	reverse(nums, 0, numsSize - k - 1);
	reverse(nums, numsSize - k, numsSize - 1);
	reverse(nums, 0, numsSize - 1);
}

5. 989. 数组形式的整数加法

989. 数组形式的整数加法
* 对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。

给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。

示例 1:
输入:A = [1,2,0,0], K = 34
输出:[1,2,3,4]
解释:1200 + 34 = 1234

示例 2:
输入:A = [2,7,4], K = 181
输出:[4,5,5]
解释:274 + 181 = 455

示例 3:
输入:A = [2,1,5], K = 806
输出:[1,0,2,1]
解释:215 + 806 = 1021

示例 4:
输入:A = [9,9,9,9,9,9,9,9,9,9], K = 1
输出:[1,0,0,0,0,0,0,0,0,0,0]
解释:9999999999 + 1 = 10000000000

提示:
1 <= A.length <= 10000
0 <= A[i] <= 9
0 <= K <= 10000
如果 A.length > 1,那么 A[0] != 0

https://leetcode-cn.com/problems/add-to-array-form-of-integer/

解法

1. 申请存储空间,因为待加数长度不定,所以要申请足够的空间
	`size > 5 ? szie+1 : 5+1`
2. 取出数组中的最后一位与数字的个位,进行相加,将加数地位存入数组,并存储进位
3. 判断待加数是否为0,如果k不为0,并且数组中元素已经加完,则将待加数按位存入数组
4. 判断数组中最前方元素是否含有空余位置,如果有则将数组向前搬移
// 输入:A = [1,2,0,0], K = 34
// 思路:取出数组最后一个元素,和k中的个位数值相加,有进位则将进位存储到进位标志位中,并且将计算结果放入数组
int* addToArrayForm(int* num, int numSize, int k, int* returnSize) 
{
	// 申请保存数据的空间
	int size = numSize > 5 ? numSize + 1 : 5 + 1;

	int* returnArr = (int*)calloc(size, sizeof(int));

	int arrLen = size - 1;
	int count = 0;
	// 按位计算
	while(numSize > 0)
	{
		k += num[numSize - 1];
		returnArr[arrLen] = k % 10;
		k /= 10;
		arrLen--;
		count++;
		numSize--;
	}

	// 如果k没有被除尽
	while (k > 0)
	{
		returnArr[arrLen--] = k % 10;
		k /= 10;
		count++;
	}

	// 判断是否用完了申请的空间,如果有空余空间没有使用,则将后方数据向前移动
	if (*returnSize < size)
	{
		memmove(returnArr, returnArr+(size - count), sizeof(int) * count);
	}
	*returnSize = count;

	return returnArr;
}

以上是关于[算法] leetcode顺序表相关题目详解的主要内容,如果未能解决你的问题,请参考以下文章

[算法] leetcode单链表相关题目详解

[算法] leetcode单链表相关题目详解

[算法] leetcode栈与队列相关题目详解

环链表相关的题目和算法[LeetCode]

⭐算法入门⭐《哈希表》中等04 —— LeetCode 347. 前 K 个高频元素

Leetcode数据结构算法题轮转数组(顺序表篇)