前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >题目练习之数组的那些事儿

题目练习之数组的那些事儿

作者头像
用户11352420
发布2024-11-07 21:35:03
580
发布2024-11-07 21:35:03
举报
文章被收录于专栏:编程学习

学习了这么久C语言知识,也了解了算法的一些概念,我们可以通过一些题目检验自己是否真正的掌握,我们一起来看看下面的练习~

练习一:合并两个有序数组

合并两个有序数组: https://leetcode.cn/problems/merge-sorted-array/description/

打开题目链接,这是一道来自力扣的题目,阅读题目,要将两个非递减数组(升序数组)合并,同时要把nums2整个数组放到nums1数组里面。题目特别给出了nums1的长度是m+n,后面n元素为0。

我们通过他给的例子来更好地理解:

也就是说nums1中前面m个元素是nums1原来的数据,后面n个元素初始化为0,以便后面合并nums2的数据。那我们很快就可以用下面这个思路——先合并再排序

思路1

先把nums2数组的元素放到nums1中的后半部分,再对nums1数组进行排序

排序方法有很多,这里展示两种:

冒泡排序

代码语言:javascript
复制
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int i = 0;
    //先合并
    for(i = m ; i< m + n ; i++)
    {
        nums1[i] = nums2[i-m];
    }
    //排序
    int j = 0;
    int temp = 0;
    for(i = 0;i < m + n -1; i++)
    {
        for(j = 0; j < m + n - 1 -i; j++)
        {
            if(nums1[j+1]<nums1[j])
            {
                temp = nums1[j+1];
                nums1[j+1] = nums1[j];
                nums1[j] = temp;
            }
        }
    }
}

提交代码可以看到它通过了测试

快速排序(qsort)

代码语言:javascript
复制
int cmp_int(void const* p1, void const* p2)
{
    return (*(int*)p1 - *(int*)p2);
}
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int i = 0;
    //先合并
    for (i = m; i < m + n; i++)
    {
        nums1[i] = nums2[i - m];
    }
    //排序
    qsort(nums1, m + n, sizeof(nums1[0]), cmp_int);
}

提交代码也是成功通过,同时我们可以看到它的时间复杂度是小于冒泡排序的,这个题有没有什么其他方法也可以优化时间复杂度变成O(N)呢?这就需要我们的下一个思路了。

思路2

既然后面是元素0,那么我们可以将两个数组从后面开始向前走进行比较,哪一个数组元素大,就把哪一个元素放在后面再往前面走。

我们可以写出下面的代码:

代码语言:javascript
复制
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    //记录每一个数组原来最后一个下标
    int l1 = m - 1;
    int l2 = n - 1;
    //记录合并数组最后一个下标
    int index = m + n - 1;
    while (l1 >= 0 && l2 >= 0)//保证数组下标不越界
    {
        //比较放入数据
        if (nums1[l1] > nums2[l2])
        {
            nums1[index--] = nums1[l1--];
        }
        else
        {
            nums1[index--] = nums1[l2--];
        }
    }
}

但是当我们提交时,它告诉我们解答错误,我们在代码中来看看这个错误的案例

nums1没有元素,nums2有一个元素 m=0,n=1 l1=0-1=-1 l2=0 l1已经越界,无法进入循环,nums2中有元素还没有放到nums1中

代码语言:javascript
复制
//nums1没有元素,nums2有一个元素
//m=0,n=1
//l1=0-1=-1
//l2=0
//l1已经越界,无法进入循环


void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    //记录每一个数组原来最后一个下标
    int l1 = m - 1;
    int l2 = n - 1;
    //记录合并数组最后一个下标
    int index = m + n - 1;
    while (l1 >= 0 && l2 >= 0)//保证数组下标不越界
    {
        //比较放入数据
        if (nums1[l1] > nums2[l2])
        {
            nums1[index--] = nums1[l1--];
        }
        else
        {
            nums1[index--] = nums2[l2--];
        }
    }
    
}

我们怎么样来处理这一种特殊情况呢?

解决方案: 当l1已经越界,nums2中有元素还没有放到nums1中时,我们可以再写一个循环将nums2的元素放到nums1中

正确代码:

代码语言:javascript
复制
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    //记录每一个数组原来最后一个下标
    int l1 = m - 1;
    int l2 = n - 1;
    //记录合并数组最后一个下标
    int index = m + n - 1;
    while (l1 >= 0 && l2 >= 0)//保证数组下标不越界
    {
        //比较放入数据
        if (nums1[l1] > nums2[l2])
        {
            nums1[index--] = nums1[l1--];
        }
        else
        {
            nums1[index--] = nums2[l2--];
        }
    }
    while (l2 >= 0)
    {
        nums1[index--] = nums2[l2--];
    }
}

练习二:删除有序数组中的重复项

这也是一道来自力扣的题目。

删除有序数组中的重复项: https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/

题目给出了原地删除,那我们就不能通过创建一个新数组来实现了。

这个题目我们知道数组是有序的,并且是一个升序数组,重复的元素一定是在一起的,所以我们可以这样做:

双指针法(双变量法) 创建两个变量pcur、dest,下标表示不同的位置, dest是初始位置下标,pcur是初始位置的下一个位置的下标 将两个位置的数据进行比较,有两种情况: 如果相等,pcur就往后面走(pcur++) 如果不相等,dest++,将pcur的值赋给dest,pcur继续往后面走(pcur++) 最后返回新数组的长度

代码如下:

代码语言:javascript
复制
int removeDuplicates(int* nums, int numsSize)
{
   //定义两个变量
	int dest = 0;//初始位置下标
	int pcur = dest + 1;//初始位置的下一个位置的下标
	while (pcur < numsSize)
	{
		//比较
		if (nums[dest] == nums[pcur])//跳过,pcur++
		{
			pcur++;
		}
		else//dest++,pcur赋值给dest后,再往后面走
		{
			dest++;
			nums[dest] = nums[pcur];
			pcur++;
		}
	}
	return dest + 1;
	//返回新数组长度
}

上面代码有点啰嗦,我们可以简单优化一下:

代码语言:javascript
复制
int removeDuplicates(int* nums, int numsSize)
{
	//定义两个变量
	int dest = 0;//初始位置下标
	int pcur = dest + 1;//初始位置的下一个位置的下标
	while (pcur < numsSize)
	{
		if (nums[dest] != nums[pcur] && ++dest != pcur)
		{
			nums[dest] = nums[pcur];
		}
		pcur++;
		//pcur往后面走
	}
	return dest + 1;
	//返回新数组长度
}

练习三:移除元素

移除元素: https://leetcode.cn/problems/remove-element/description/

题目也是给出了原地删除,那我们就不能通过创建一个新数组来实现。

我们也可以使用 双指针法(双变量法)

创建两个变量 pcur、dest指向初始位置的下标 将pcur数据与val进行比较,有两种情况: 如果相等,pcur就往后面走(pcur++) 如果不相等,将pcur的值赋给dest,pcur、dest往后面走(pcur++、dest++) 最后返回元素个数,也就是dest(dest前面已经++,不需要再+1)

代码语言:javascript
复制
int removeElement(int* nums, int numsSize, int val)
{
	//创建两个变量下标指向初始位置
	int pcur = 0;
	int dest = 0;
	while (pcur < numsSize)
	{
		if (nums[pcur] == val)//跳过
		{
			pcur++;
		}
		else//保留
		{
			nums[dest++] = nums[pcur++];
			//dest、pcur使用后++
		}
	}
	return dest;
	//返回元素个数,dest前面已经++
}

我们可以看到运行通过~

♥♥♥本篇博客内容结束,期待与各位未来的优秀程序员交流,有什么问题请私信♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 练习一:合并两个有序数组
    • 思路1
      • 思路2
      • 练习二:删除有序数组中的重复项
      • 练习三:移除元素
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档