每日一题(顺序表)

顺序表

  • 消失的数字
  • 轮转数组
  • 移除元素
  • 合并两个有序数组

消失的数字

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?

注意:本题相对书上原题稍作改动

示例 1:
输入:[3,0,1]
输出:2

示例 2:
输入:[9,6,4,2,3,5,7,0,1]
输出:8

思路:
由于缺失一个数,所以可以先计算出 0~n 的异或结果,再依次与数组中的元素异或,最后的结果就是缺失的数字

int missingNumber(int* nums, int numsSize){
    int x=0;
    for(int i=0;i<=numsSize;i++)
    {
        x^=i;// 计算 0~n 的异或结果
    }
    for(int i=0;i<numsSize;i++)
    {
        x^=nums[i];// 依次异或数组中的元素
    }
    return x;
}

轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 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]

思路1:
每次将数组最后一个元素取出并放到数组的开头,重复 k 次操作实现数组的旋转
思路2:
利用双指针,将范围内的元素进行交换
对 k 进行取模处理,避免 k 大于数组长度造成多余的旋转

// 时间复杂度 O(N*K)
void rotate(int* nums, int numsSize, int k) {
    while(k--)
    {
        int temp=nums[numsSize-1];
        for(int end=numsSize-2;end>=0;end--)
            nums[end+1]=nums[end];
        nums[0]=temp;
    }
}


// 时间复杂度 O(1)
void Reverse(int nums,int left,int right)
{
	while(left < right)
	{
		int temp=nums[left];
		nums[left]=nums[right];
		nums[right]=temp; left++; right--;
	 } 
}
void rotate(int nums, int numsSize, int k) {
	if(k >= numsSize)
	{
		k=k%numsSize; // 对 k 进行取模处理,避免 k 大于数组长度造成多余的旋转
	}
	// 1 2 3 4 7 6 5
	Reverse(nums,numsSize-k,numsSize-1); // 反转后面的 k 个元素
	// 4 3 2 1 7 6 5
	Reverse(nums,0,numsSize-k-1); // 反转前面的 numsSize - k 个元素
	// 5 6 7 1 2 3 4
	Reverse(nums,0,numsSize-1); // 反转整个数组
}

移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]

思路:
使用双指针,一个指向源位置,一个指向目标位置,遍历数组,并将不等于目标值的元素移到前面

int removeElement(int* nums, int numsSize, int val) {
    int src=0; // 源位置指针
    int dst=0; // 目标位置指针
    while(src < numsSize)
    {
        if(nums[src]!=val) // 当源位置指针指向的元素不等于目标值时
        {
            nums[dst]=nums[src]; // 将该元素移到目标位置
            dst++; // 目标位置指针后移
            src++; // 源位置指针后移
        }
        else
            src++; // 当源位置指针指向的元素等于目标值时,只移动源位置指针
    }
    return dst; // 返回移除目标值后的新数组长度
}

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6]

思路:
思路:从后向前合并两个数组,将较大的数字放到 nums1 的末尾,直到所有元素都被合并

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    // 将较大的数字放到nums1中
    int end1=m-1; // 第一个数组的末尾指针
    int end2=n-1; // 第二个数组的末尾指针
    int end=m+n-1; // 合并后数组的末尾指针

    while(end1>=0 && end2>=0) // 循环直到其中一个数组的元素全部合并完成
    {
        if(nums1[end1] > nums2[end2]) // 比较两个数组末尾的元素大小
        {
            nums1[end]=nums1[end1]; // 将较大的元素放到合并后数组的末尾
            end--; // 指针前移
            end1--; // 数组1的末尾指针前移
        }
        else
        {
            nums1[end]=nums2[end2]; // 将较大的元素放到合并后数组的末尾
            end--; // 指针前移
            end2--; // 数组2的末尾指针前移
        }
    }
    while(end2 >= 0) // 若数组2还有剩余元素
    {
        nums1[end]=nums2[end2]; // 将剩余的元素放到合并后数组的末尾
        end--; // 指针前移
        end2--; // 数组2的末尾指针前移
    }
}

你可能感兴趣的:(leetcode,数据结构,c语言)