|
| 1 | +# 题目描述(简单难度) |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +给定一个有序数组,依旧是二分查找,不同之处是如果没有找到指定数字,需要返回这个数字应该插入的位置。 |
| 6 | + |
| 7 | +这道题比较简单,在二分查找的基础上,只要想清楚返回啥就够了。想的话,就考虑最简单的情况如果数组只剩下 2 5,target 是 1, 3, 6 的时候,此时我们应该返回什么就行。 |
| 8 | + |
| 9 | +```java |
| 10 | +public int searchInsert(int[] nums, int target) { |
| 11 | + int start = 0; |
| 12 | + int end = nums.length - 1; |
| 13 | + if (nums.length == 0) { |
| 14 | + return 0; |
| 15 | + } |
| 16 | + while (start < end) { |
| 17 | + int mid = (start + end) / 2; |
| 18 | + if (target == nums[mid]) { |
| 19 | + return mid; |
| 20 | + } else if (target < nums[mid]) { |
| 21 | + end = mid; |
| 22 | + } else { |
| 23 | + start = mid + 1; |
| 24 | + } |
| 25 | + } |
| 26 | + //目标值在不在当前停的位置的前边还是后边 |
| 27 | + if(target>nums[start]){ |
| 28 | + return start + 1; |
| 29 | + } |
| 30 | + //如果小于的话,就返回当前位置,跑步超过第二名还是第二名,所以不用减 1。 |
| 31 | + else{ |
| 32 | + return start; |
| 33 | + } |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +时间复杂度:O(log(n))。 |
| 38 | + |
| 39 | +空间复杂度:O(1)。 |
| 40 | + |
| 41 | +这道题不难,但是对于二分查找又有了一些新认识。 |
| 42 | + |
| 43 | +首先,一定要注意,数组剩下偶数个元素的时候,中点取的是左端点。例如 1 2 3 4,中点取的是 2。正因为如此,我们更新 start 的时候不是直接取 mid ,而是 mid + 1。因为剩下两个元素的时候,mid 和 start 是相同的,如果不进行加 1 会陷入死循环。 |
| 44 | + |
| 45 | +然后上边的算法,返回最终值的时候,我们进行了一个 if 的判断,那么能不能避免呢。 |
| 46 | + |
| 47 | +* 第一种思路,参考[这里](https://leetcode.com/problems/search-insert-position/discuss/15080/My-8-line-Java-solution)。 |
| 48 | + |
| 49 | + 首先为了让 start 在循环的时候多加 1,我们将循环的 start < end 改为 start <= end。 |
| 50 | + |
| 51 | + 这样就会出现一个问题,当 start == end,此时 mid 不仅等于了 start 还会等于 end,所以之前更新 end 是直接赋 mid,现在需要改成 end = mid - 1,防止死循环。这样就达到了目标。 |
| 52 | + |
| 53 | + ```java |
| 54 | + public int searchInsert(int[] nums, int target) { |
| 55 | + int start = 0; |
| 56 | + int end = nums.length - 1; |
| 57 | + if (nums.length == 0) { |
| 58 | + return 0; |
| 59 | + } |
| 60 | + while (start <= end) { |
| 61 | + int mid = (start + end) / 2; |
| 62 | + if (target == nums[mid]) { |
| 63 | + return mid; |
| 64 | + } else if (target < nums[mid]) { |
| 65 | + end = mid - 1; |
| 66 | + } else { |
| 67 | + start = mid + 1; |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + return start; |
| 72 | + |
| 73 | + } |
| 74 | + ``` |
| 75 | + |
| 76 | + |
| 77 | +* 第二种思路,参考[这里](https://leetcode.com/problems/search-insert-position/discuss/15110/Very-concise-and-efficient-solution-in-Java)。 |
| 78 | + |
| 79 | + 我们开始更新 start 的时候,是 mid + 1,如果剩两个元素,例如 2 4,target = 6 的话,此时 mid = 0,start = mid + 1 = 1,我们返回 start + 1 = 2。如果 mid 是右端点,那么 mid = 1,start = mid + 1 = 2,这样就可以直接返回 start 了,不需要在返回的时候加 1 了。 |
| 80 | + |
| 81 | + 怎么做到呢?最最开始的时候我们取 end 的时候是 end = nums.length - 1。如果我们改成 end = nums.length,这样每次取元素的时候,如果和之前对比,取到的就是右端点了。这样的话,最后返回的时候就不需要多加 1 了。 |
| 82 | + |
| 83 | + ```java |
| 84 | + public int searchInsert(int[] nums, int target) { |
| 85 | + int start = 0; |
| 86 | + int end = nums.length; |
| 87 | + if (nums.length == 0) { |
| 88 | + return 0; |
| 89 | + } |
| 90 | + while (start < end) { |
| 91 | + int mid = (start + end) / 2; |
| 92 | + if (target == nums[mid]) { |
| 93 | + return mid; |
| 94 | + } else if (target < nums[mid]) { |
| 95 | + end = mid; |
| 96 | + } else { |
| 97 | + start = mid + 1; |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + return start; |
| 102 | + |
| 103 | + } |
| 104 | + ``` |
| 105 | + |
| 106 | +# 总 |
| 107 | + |
| 108 | +虽然题很简单,但对二分查找有了更多的理解。 |
0 commit comments