zoukankan      html  css  js  c++  java
  • LeetCode 新题: Find Minimum in Rotated Sorted Array 解题报告-二分法模板解法

    Find Minimum in Rotated Sorted Array


    Question Solution
    Suppose a sorted array is rotated at some pivot unknown to you beforehand.

    (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

    Find the minimum element.

    You may assume no duplicate exists in the array.

    SOLUTION 1:
    这个题目trick的地方在于,它的旋转pivot次数未知。所以有可能它转了一圈又转回了原处

    所以我们代码要处理2种情况:
    我们还是用二分法来做。比起全部扫一次,二分法可以做到LogN的复杂度。
    1. Sorted  

      这种情况简单,先计算出mid的值,如果它处在左右的中间,证明这个数列是正常的sorted,直接返回左边。

    2. 中间断开(也就是说旋转过)
    我们的目的是要找出存在断口的地方。所以我们可以每次求一下mid的值,把mid 跟左边比一下,如果是正常序,就丢掉左边,反之丢掉右边,不断反复直到找到断口。
    分析一下:
    比如4 5 6 7 0 1 2  从中间断开后,它是由一个有序跟一个无序的序列组成的。
    如果left = 0, right = 6,mid = 3, 那么4, 5, 6, 7 是正序, 7, 0, 1, 2是逆序,所以我们要丢掉左边。这样反复操作,直到数列中只有2个数字,就是断开处,这题我们会得到7,0,返回后一个就可以了。

    以下图示简单描述了通过三步操作逐步逼近断口处。每一次我们可以扔掉一半,速度是LogN.



    注意,丢掉半边时,mid不可以丢掉,因为有可能mid就是答案。
    例子: 3, 1, 2 的时候,3, 1是逆序,1, 2是正序,如果你扔掉1,2你就丢掉了答案。
     1 // Solution 1:
     2     public int findMin1(int[] num) {
     3         if (num == null || num.length == 0) {
     4             return 0;
     5         }
     6         
     7         if (num.length == 1) {
     8             return num[0];
     9         }
    10         
    11         
    12         // 至少有2个元素,才有讨论的价值 
    13         int l = 0;
    14         int r = num.length - 1;
    15         
    16         while (l < r) {
    17             int mid = l + (r - l)/2;
    18             // Means that there is no rotate.
    19             if (num[mid] >= num[l] && num[mid] <= num[r]) {
    20                 return num[0];
    21             }
    22             
    23             // rotate > 0的情况 
    24             if (l == r - 1) {
    25                 // 当只余下2个元素的时候,这里是断点,右边的是小值
    26                 return num[r];
    27             }
    28             
    29             if (num[mid] >= num[l]) {
    30                 // The left side is sorted. Discard left.
    31                 l = mid;
    32             } else {
    33                 // The right side is sorted.
    34                 r = mid;
    35             }
    36         }
    37         
    38         return 0;
    39     }
    View Code

    SOLUTION 2:

    采用九章算法的二分法模板来解:
    这个模板最大的好处是 while(left < right - 1) 这样的话,终止时就一定是left = right - 1,而且mid 一直会是在中间,不会靠到left去。判断起来会相当
    便利。
    常见bug:

    // bug 1: should not use l = m + 1 and r = m - 1.
    // this may discard the minumul value.

    A example: 3, 1, 2.

     1 // solution 2:
     2     public int findMin(int[] A) {
     3         if (A == null || A.length == 0) {
     4             return 0;
     5         }
     6         
     7         if (A.length == 1) {
     8             return A[0];
     9         } else if (A.length == 2) {
    10             return Math.min(A[0], A[1]);
    11         }
    12         
    13         // 至少有3个元素,才有讨论的价值 
    14         int l = 0;
    15         int r = A.length - 1;
    16         
    17         while (l < r - 1) {
    18             int m = l + (r - l) / 2;
    19             
    20             // means that there is no rotate.
    21             if (A[m] < A[r] && A[m] > A[l]) {
    22                 return A[0];
    23             }
    24             
    25             // left side is sorted.
    26             if (A[m] > A[l]) {
    27                 l = m;
    28             } else {
    29                 r = m;
    30             }
    31         }
    32         
    33         return A[r];
    34     }
    View Code
     
    所以以后一定要多使用模板化的编程 ,特别是这里总结的二分法模板:
     1         while (l < r - 1) {
     2             int m = l + (r - l) / 2;
     3             
     4             // means that there is no rotate.
     5             ... 这里添加各种退出条件,比如找到了目标值等 8             
     9             // left side is sorted.
    10             if (A[m] > A[l]) {
    11                 l = m;
    12             } else {
    13                 r = m;
    14             }
    15         }    

     

     SOLUTION 3:

     在解答2的基础之上,可以把判断是否rotated的statement去掉,然后每次丢弃有序数列时,先丢弃右边的。这样子即使是从未rotated的也没有关系,因为一直是丢右边的

    直到余下左边最后2个。

     1 public int findMin(int[] num) {
     2         if (num == null || num.length == 0) {
     3             return 0;            
     4         }
     5         
     6         int l = 0;
     7         int r = num.length - 1;
     8         
     9         while (l < r - 1) {
    10             int m = l + (r - l) / 2;
    11             
    12             if (num[m] < num[r]) {
    13                 // bug 1: should not use l = m + 1 and r = m - 1. 
    14                 // this may discard the minumul value.
    15                 r = m;
    16             } else {
    17                 l = m;
    18             }
    19         }
    20         
    21         return Math.min(num[l], num[r]);
    22     }
    View Code 

     SOLUTION 4:

     在解答3的基础之上,预判断是不是旋转过,这样如果没有旋转我们可以直接把解算出即可。

     1 public int findMin(int[] num) {
     2         if (num == null || num.length == 0) {
     3             return 0;            
     4         }
     5         
     6         int l = 0;
     7         int r = num.length - 1;
     8         
     9         if (num[l] < num[r]) {
    10             return num[l];
    11         }
    12         
    13         while (l < r - 1) {
    14             int m = l + (r - l) / 2;
    15             
    16             if (num[m] < num[r]) {
    17                 // bug 1: should not use l = m + 1 and r = m - 1. 
    18                 // this may discard the minumul value.
    19                 r = m;
    20             } else {
    21                 l = m;
    22             }
    23         }
    24         
    25         return Math.min(num[l], num[r]);
    26     }
    View Code

    FOLLOW UP:

    LeetCode 新题: Find Minimum in Rotated Sorted Array II 解题报告-二分法模板解法

    GitHub:

    GitHub代码链接
  • 相关阅读:
    Win7下使用TortoiseGit设置保存密码
    MacOS软件清单
    ubuntu安装python
    Mac使用SSH连接远程服务器
    CentOS常用命令
    Docker追加容器端口映射
    Docker安装CentOS7
    Windows操作路由表
    Docker部署MySQL8并实现远程连接
    Qt——容器类(译)
  • 原文地址:https://www.cnblogs.com/yuzhangcmu/p/4049030.html
Copyright © 2011-2022 走看看