代码随想录算法训练营第一天|704 二分查找、27移除元素、997 有序数组的平方

一、704 二分查找

定义:

        折半查找也称二分查找,是一种高效的查找算法.但折半查找要求有数据必须采用顺序存储(顺序表或数组,不能使用链表),表中数据必须有序(假设递增有序)。

算法:

        需要和中间的数(middle)作对比,如果目标数值(target)小于中间值,则将在中间值的左边范围进行查找,如果目标数值大于中间值,则将在中间值得右边范围进行查找,重复操作,直到目标值等于中间值即为查找成功,若没有找到则查找失败。

题目:

代码:

int search(int* nums, int numsSize, int target) {
	//采用左闭右闭区间
	int left = 0;
	int right = numsSize - 1;
	while (left <= right)
	{
		int middle = (left + right) / 2;
		if (nums[middle] > target)
			right = middle - 1;
		else if (nums[middle] < target)
			left = middle + 1;
		else if (nums[middle] == target)
			return middle;
	}
	return -1;
	//采用左闭右开区间
	int left = 0;
	int right = numsSize;
	while (left < right)
	{
		int middle = (left + right) / 2;
		if (nums[middle] > target)
			right = middle;
		else if (nums[middle] < target)
			left = middle + 1;
		else if (nums[middle] == target)
			return middle;
	}
	return -1;
}

代码理解(细节):

        在这里,我使用了两种方法来完成二分查找,一个是左闭右闭,即[   ],另一个是左闭右开,即[   )。

        两种方法的区别在于边界不同,这也导致了两种代码对于边界的处理不一样。

左闭右闭区间原因左闭右开区间原因
right的取值middle-1middle
left</<=right<=是出于合法区间内<右值不能取
更新right值right=middle-1middle已经判断过,不需要在判断right=middle右值不能取,所以middle还没判断

 二、27 移除元素

题目:

代码:

int removeElement(int* nums, int numsSize, int val) {
     //暴力解法(双循环)
	int size = numsSize;
	for (int i = 0; i < size; i++)
	{
		if (nums[i] == val)
		{
			for (int j = i + 1; j < size; j++)
            {
                nums[j - 1] = nums[j];
            }
		i--;
        size--;
        }
	
	}
	return size;

    //双指针(一个循环)
    int fast;//快指针
    int slow=0;//慢指针
    for(fast=0;fast<numsSize;fast++)
    {
        if(nums[fast]!=val)
        {
            nums[slow]=nums[fast];
            slow++;
        }
    }
    return slow;
}

代码理解(细节):

在这个,我使用了两种解法。

        第一种是暴力法,它是通过双层循环实现。在第一层循环遍历数组时,如果出现等于val的情况,那么,第二层循环将把val的后一个数赋值到当前位置,即覆盖掉val。

        第二种方法是双指针,它则是通过在一层循环内的两个指针实现。第一个指针为快指针,第二个指针慢指针。两个指针一起出发,当遇到val时,慢指针不懂,快指针向后移动,然后将非val的值赋值给慢指针所在位置,实现覆盖(删除)val的操作。

三、997 有序数组的平方

题目:

代码:

int* sortedSquares(int* nums, int numsSize, int* returnSize) {
    *returnSize = numsSize;

    int left = 0;
    int right = numsSize -1;

    int *ans = (int *)malloc(sizeof(int)*numsSize);
    int k = numsSize-1;
    for(int i =0 ,j=numsSize-1;i<=j;)
    {
        if(nums[i]*nums[i]>nums[j]*nums[j])
        {
            ans[k] = nums[i]*nums[i];
            k--;
            i++;
        }
        else{
            ans[k] = nums[j]*nums[j];
            k--;
            j--;
        }
    }
    return ans;
}

代码理解(细节): 

关于这道题,小编主要学习了两种思路,一种是暴力法,一种是双指针解法。

        首先,我来简单说一下暴力解法,首先将数组内的所有数字直接平方,然后利用快速排序的方法变成递增数组,这种方法的时间复杂度取决于快速排序的时间复杂度,为O(nlogn)。

        因此,我又学习了第二种方法,也就是代码所展示的方法,双指针解法。这个方法是采用两个指针指向原数组,一个指针在最前,一个指针在最后(因为不管数组内是否有负数,平方后的最大值一定都在两边,不可能在最中间)。通过比较两个指针指向数字平方后的结果,哪个指针指向的数字平方大,就把该指针指向的数字平方存入新数组,并且该指针进行移动(若为前指针则向后移动,若为后指针则向前移动)。在这里,我们要注意,为了保证新数组是递增数组,我们要把数字从后向前保存,即k=numsSize - 1;和k--;这样就保证了每来一个新平方数都是放在后面的。

【小编有话说】

        欢迎来到小编新开的栏目~

        可能会有朋友觉得这个第一篇文章为什么感觉水水的,其实它不水,只是小编是在第二天的时候进的训练营,本身已经落了一天,小编还不远放弃这篇文章以及天数,只好浓缩一下了。但是,浓缩的都是精华(觉得不是也请口下留情)。

        有种计划赶不上变化的感觉,前两天小编还在思考新增数据结构或者C++,今天就新开了一个意想不到的栏目!但是,小编的目标始终不变,那就是和大家一起学习,一起进步!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值