LeetCode 35 - Search Insert Position


https://leetcode.com/problems/search-insert-position/
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
http://www.bijishequ.com/detail/134759?p=66
一直觉得Binary Search是非常好的考察正确性证明思路的一类题。因为它对区间……
下面就以这道题的原始Binary Search为例看一下为什么我们的代码是正确的,后面的题不会再这样繁琐的证明了。通过这道题了解思路和技巧,后面的题我们只要把握住关键点就可以了。
首先我们要搜索target的位置,所以用low和high组成的区间表示搜索范围,不变量Invariant就是:MustBe(low,high)表示target一定存在于区间[low,high],否则它不存在于nums数组。接下来就是运用循环迭代不断缩小这个区间,最重要的是在这个过程中保持Invariant始终为真,最终我们得到的就一定是正确的结果:
  1. 初始化(Initialization):初始时,MustBe(0,nums.length-1)包含了整个数组,按照MustBe的定义来说target要么存在于整个数组要么不存在,这肯定为真。于是Invariant初始状态没问题!
  2. 维护(Preservation):对于这道题很容易,如果target在前一半,那么MustBe(low,mid-1),所以更新high=mid-1就能维持Invariant为真了。反之,更新low=mid+1就行了。
  3. 终止(Termination):能够清楚看出在循环过程中,low和high区间是在不断shrink。
有了以上三条,当循环终止时low > high并且MustBe(low,high)为真,于是我们就能知道target不存在。其实个人感觉:MustBe(low,high)应该叫做CanBe(low,high)更贴切,因为target可能不存在于数组中。所以最后CanBe(low,high)并且low > high,使得CanBe变成了MustNotBe。但也许CanBe语气比较弱,不像断言?后面我们会看到153-Find Minimum in Rotated Sorted Array找Minimum最小值,这道题的Invariant叫MustBe才比较合适!

1.3 循环终止前的样子

但这道题还没完,可以说最关键的一点来了:要返回插入位置而不是-1就完事了。这就要求我们仔细分析一下循环停止前那一刻是什么样子。因为low < high不可能直接跳到low > high,low = high - 1是倒数第二轮的情况,而最后一轮一定是low = high。于是就有low = mid = high,如果target > nums[mid],那么会导致low = mid + 1,low就是插入位置。而如果target < nums[mid],那么会导致high = mid - 1,low同样是插入位置。所以不断最后一轮是什么情况,low一定是插入位置

1.4 解题关键点

这道题的代码非常标准,可以作为下面各道题Solution的模板。做下面各题时如果赶时间,比如面试时,可以先把上面的代码骨架写出来,再思考各个关键点。那Binary Search类型题都还有哪些变化,要把握住哪些关键点呢?在开始各个击破之前,先总结一下:
以二分查找为蓝本,这一类查找类型题还是能玩出不少变化的,例如最关键的几点有:
  1. low和high初始值:大部分都是数组的范围从0到N-1,个别像278-First Bad Version和374-Guess Number Higher or Lower是从1到N。
  2. 循环结束条件: 
    2.1 如果我们要找的target一定存在的话,那用low < high,最后low = high导致循环结束,low位置就是我们要找的数字了。这种一定存在的问题有:69-Sqrt、153-Find Minimum in Rotated Sorted Array、162-Find Peak Element、278-First Bad Version、374-Guess Number Higher or Lower。 
    2.2 如果target不一定存在的话,就要用low <= high,最终low大于high导致循环退出,说明target不存在。
  3. 区间缩减: 
    3.1 首先是如何确定缩减方向:最简单的是比较A[low/high]和A[mid],复杂的如33-Search in Rotated Sorted Array还要比较是不是真的在那个区间内,还有就是367-Valid Perfect Square比较平方数的。 
    3.2 其次是如何确定缩减量。原则就是:确定搜索区间的缩减方向后,看如何更新low和high能保证Invariant为真。普通查找如35-Search Insert Position很简单,low=mid+1,high=mid-1。像278-First Bad Version中确定mid是Bad的话则high=mid,但mid不是Bad的话那么low=mid+1。69-Sqrt(x)中mid的平方小于x不代表mid一定小于x的平方根,例如2*2<5,所以low=mid,但反之mid一定大于x的平方根,所以high=mid+1。严重注意:high=mid没关系,但low=mid有可能导致死循环。因为low=high-1时low=mid,如果又进入low=mid分支相当于搜索区间没缩小。但high一定大于mid,所以不会造成死循环。方法就是:在low=high-1之前就跳出循环,然后自行判断。
  4. 最终结果确定:要看清题意最后需要返回什么,是-1,下标,还是值。
https://discuss.leetcode.com/topic/7874/my-8-line-java-solution
    public int searchInsert(int[] A, int target) {
        int low = 0, high = A.length-1;
        while(low<=high){
            int mid = (low+high)/2;
            if(A[mid] == target) return mid; // not work if there is duplicate
            else if(A[mid] > target) high = mid-1;
            else low = mid+1;
        }
        return low;
    }
https://discuss.leetcode.com/topic/31499/very-concise-and-efficient-solution-in-java
but I think if nums[mid] == target in the some early iteration, ur solution will be potentially wasting calculation cycles by not treating that as one of the cases, although more concise?


It's very good question. As you said, the algorithm does waste a little time for some cases in which @target is found very early. But to support early RETURN, you have to add a IF branch in WHILE block, which costs more time than the former one for general cases. Besides, concise solutions are often easy to understand and therefore to be optimized.
public int searchInsert(int[] nums, int target) {
    int low = 0, high = nums.length;
    while(low < high) {
        int mid = low + (high - low) / 2;
        if(nums[mid] < target)
            low = mid + 1;
        else
            high = mid;
    }
    return low;
}
This could be the most concise solution. And the point is: it also handle duplicate!
public int searchInsert(int[] nums, int target) {
    return firstOccurrenceRecur(nums,target,0,nums.length-1);
}
public int firstOccurrenceRecur(int[] nums, int target, int low, int high) {
    if (low > high) { return low; }
    int mid = low + ( (high - low) >> 1 );
    if (nums[mid] < target) {
        return firstOccurrenceRecur(nums,target,mid + 1,high);
    } else {
        return firstOccurrenceRecur(nums,target,low,mid-1);
    }
}
X. Recursion
https://discuss.leetcode.com/topic/2661/simple-binary-search-solution
Only two cases:
1 if found, just return current index
2 if not found, return next index where the search end
int search(int A[], int start, int end, int target) {
    if (start > end) return start;
    int mid = (start + end) / 2;
    if (A[mid] == target) return mid;
    else if (A[mid] > target) return search(A, start, mid - 1, target);
    else return search(A, mid + 1, end, target);
}
int searchInsert(int A[], int n, int target) {
    return search(A, 0, n - 1, target);
}


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts