【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置

【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置

  • 一、题目描述
  • 二、解题
    • 方法1——直接遍历
      • 1.1、思路分析
      • 1.2、代码实现
    • 方法2——二分法
      • 2.1、思路分析
      • 2.2、代码实现

一、题目描述

原题连接: LeetCode 35. 搜索插入位置

题目描述:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,则返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4

二、解题

方法1——直接遍历

1.1、思路分析

直接遍历数组,如果找到target就返回其下标,当出现nums[i] < target && nums[i + 1] > target时,i + 1就是我们要顺序插入的下标。

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

int searchInsert1(int* nums, int numsSize, int target) {
	assert(nums);
	// 特殊情况特殊处理
	if (target < nums[0]) {
		return 0;
	} else if (target > nums[numsSize - 1]) {
		return numsSize;
	}
	int i = 0;
	for (i = 0; i < numsSize; i++) {
		if (nums[i] == target) {
			return i;
		}
		else if (nums[i] < target && nums[i + 1] > target) {
			return i + 1;
		}
	}
	return numsSize;
}

时间复杂度:O(n),n为数组元素个数,我们只需要遍历一遍数组即可。
空间复杂度:O(1),我们只需要用到常数级的额外空间。

方法2——二分法

2.1、思路分析

注意题目中说的是一个排序数组,那么上面的方法就显得太复杂了,在一个排序数组中寻找一个目标值,我们很容易的就能想到用二分法。
但有些人可能就会疑惑,用二分法查找如果找到了那还好说,但若是找不到呢?该怎么找到要顺序插入的下标呢?
这个其实很简单,我们直接返回left就行,思路如下:
【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置_第1张图片
当我们停下循环的时候,一定是left > right 的时候,这也一定是left向后移动的结果,而且只有当nums[mid] > target的时候才执行的left = mid + 1 (这里的mid是上一轮的mid,也即left == right时mid)
所以可以肯定的是,上一轮mid指向的元素小于target,
那么怎么确定当left > right时,left指向的元素就一定大于target呢?
请看下图:
【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置_第2张图片

我们需要思考,为什么left和right会重合呢?是不是当mid指向的元素大于target的时候,执行的right = mid - 1才能让left和right重合呢?所以我们可以确定当left和right将要重合是,上一轮的left、mid和right一定是像上图一样,排成一排的。
所以如果下一轮(left和right重合时),left还要左移的话,就只能移动到上一轮mid指向的位置:
【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置_第3张图片
所以我们也就能确定,当left > ritht时,有nums[right] < target < nums[left]了。
故我们最后直接返回left即可。

2.2、代码实现

有了以上分析,那我们写起代码来也就水到渠成了:

int searchInsert2(int* nums, int numsSize, int target) {
	assert(nums);
	// 特殊情况特殊处理
	if (target < nums[0]) {
		return 0;
	}
	else if (target > nums[numsSize - 1]) {
		return numsSize;
	}
	int left = 0;
	int right = numsSize - 1;
	int mid = 0;
	while (left <= right) {
		mid = left + (right - left) / 2;
		if (target == nums[mid]) {
			return mid;
		}
		else if (target > nums[mid]) {
			left = mid + 1;
		}
		else if (target < nums[mid]) {
			right = mid - 1;
		}
	}
	return left;
}

时间复杂度:O(logn),n为数组元素个数。
空间复杂度:O(1),我们只需要用到常数级的额外空间。

你可能感兴趣的:(刷题之路——简单篇,leetcode,算法,数据结构)