数据结构初阶-顺序表的应用

这篇我将从力扣的三个题目入手,来加深对顺序表的作用的关注。

1.移除元素

题目链接:https://leetcode.cn/problems/remove-element/description

思路:双指针法,第一个变量src指向原位置的下标,dst变量指向移位后的下标,即为src在这里一直遍历完整个数组,然后我们需要一直赋值,nums[dst]=nums[src],dst在遇到与k相同的元素时就不会++,这样就可以使这个数一直赋值给这个前面的位置,理解了思路就开始敲代码了:

int removeElement(int* nums, int numsSize, int val) 
{
    int dst = 0;
    int src = 0;
    while (src < numsSize)
    {
        if (nums[src] != val)
        {
            nums[dst] = nums[src];
            dst++;
        }
        src++;
    }
    return dst;
    //这个不能为dst+1,我们可以认为nums[dst]是没有赋值的位置
}

提交代码后发现没有问题,如果我们按照常规思考,我们都想是用两个循环来依次移动数组元素,如我所写:

int removeElement(int* nums, int numsSize, int val)
{
    int i, j, k = 0;
    for (i = 0; i < numsSize; i++)
    {
        if (nums[i] == val)
        {
            k++;
            for (j = i; j < --numsSize; j++)
            {
                nums[j] = nums[j + 1];
            }
        }
    }
    return numsSize;
}

这个代码时间复杂度为O(n^2),不好的解法。

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

题目链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description

思路:查找重复数据,然后把重复数据覆盖,我们和上一题解决方法可以相同,但是要改一下,我们需要dst指向初始位置,然后src指向dst指向的下一个位置,然后看是否相等,如果相等,我们需要把src++,dst不变,最终返回的是dst+1,如果不相等,则两者都加1.思路分析完了,我们开始写代码吧:

int removeDuplicates(int* nums, int numsSize)
{
    int dst = 0;
    int src = 1;
    while (src <= numsSize)
    {
        if (nums[dst] == nums[src])
        {
            src++;
        }
        else
        {
            dst++;
            nums[dst] = nums[src];
            //不能先赋值再+1,不然会把之前位置的值给覆盖掉,最终结果会少一个值
            //这题不像之前的题目,之前的题目是等待赋值,而这个题目是要先比较再看是否要赋值
            src++;
        }
    }
    return dst + 1;
}

但是发现报错了,我们要考虑是否出现数组越界的情况,所以我们需要把循环条件改为src

int removeDuplicates(int* nums, int numsSize) 
{
    int src = 1;
    int dst = 0;
    while (src < numsSize)
    {
        if (nums[src] != nums[dst] && ++dst != src)
        {
            nums[dst] = nums[src];
        }
        src++;
    }
    return dst + 1;
}

3.合并两个有序数组

题目链接:https://leetcode.cn/problems/merge-sorted-array/description/

思路1:先合并两个数组,再进行冒泡排序,这个算法比较简单粗暴,比较容易想到,所以我们只需要敲一下代码即可:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{
    int i, j;
    for (i = m; i < m + n; i++)
    {
        nums1[i] = nums2[i - m];
    }
    for (i = 0; i < m + n - 1; i++)
    {
        for (j = 0; j < m + n - 1 - i; j++)
        {
            if (nums1[j] > nums1[j + 1])
            {
                int tmp = nums1[j];
                nums1[j] = nums1[j + 1];
                nums1[j + 1] = tmp;
            }
        }
    }
}

但是这个算法简单,时间复杂度大,为O(n^2),讲一下另外一个算法:

定义三个变量,index指向第一个数组第m+n个位置,i指向第一个数组第m个位置,j指向第2个数组第n 个位置(我们需要从大到小比较赋值,如果从小到大比较,比较复杂,和第一个算法没有多大区别)。我们可以写出下列代码:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{
    int index = m + n - 1;//这是下标
    int i = m - 1;
    int j = n - 1;
    while (i > 0 && j > 0)
    {
        if (nums1[i] > nums2[j])
        {
            nums1[index--] = nums1[i];
        }
        else
        {
            nums1[index--] = nums2[j];
        }
    }
}

但是我们测试时用例不通过,这是因为如果nums1没有数据,无法进入循环,而且如果nums2还有数据的话,也没有拷贝过来,所以这个是不行的,故有

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int index = m + n - 1;
    int i = m - 1;
    int j = n - 1;
    while (i >= 0 && j >= 0)
    {
        if (nums1[i] > nums2[j])
        {
            nums1[index--] = nums1[i--];
        }
        else
        {
            nums1[index--] = nums2[j--];
        }
    }
    //我们如果是nums1的数据没拷贝完全,本来就在第一个数组中,我们没必要拷贝,所以只用考虑第二个数组没有完全拷贝的情况
    while(j >= 0)
    {
        nums1[index--] = nums2[j--];
    }
}

这是三个题目,难度不是很大,但是我们需要理解里面的思想,并应用在之后的学习中,下节讲:单链表,不见不散,喜欢的可以一键三连哦。

你可能感兴趣的:(数据结构)