【问题标题】:Minimum in rotated sorted array旋转排序数组中的最小值
【发布时间】:2021-01-29 03:41:27
【问题描述】:

我在看this leetcode挑战:

假设一个按升序排序的数组在某个枢轴处旋转 你事先不知道的。

(即,[0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2])。

找到最小的元素。

您可以假设数组中不存在重复项。

我找到了这个解决方案on repl.it

function findMin(nums) {
    if (nums.length === 1) { //Edge
        return nums[0];
    }

    let left = 0, right = nums.length - 1 //Two pointers 

    if (nums[right] > nums[0]) { //Sorted array case
        return nums[0];
    }

    while (left < right) { //Shifted unsorted array 
        const mid = Math.floor((left + right) / 2); 
        if (nums[mid] > nums[right]) left = mid + 1; //If midpoint is larger than last element, look right
        else right = mid; //Else look left 
  }
  return nums[left];
}

我的问题与以下行背后的逻辑有关:

 if (nums[mid] > nums[right]) left = mid + 1;

我一直在尝试在纸上编写示例,但是有人可以解释为什么上面的行是正确的逻辑吗?是不是因为移位数组中所有最小的元素总是在数组的右边?

【问题讨论】:

    标签: arrays algorithm binary-search


    【解决方案1】:

    您已经使用以下方法检查了非移位排序数组:

    if (nums[right] > nums[0]) {                            
        //Sorted array case
            return nums[0];
        }
    

    现在举个例子:

    3 4 5 2 1

    代码:

    while (left < right) { //Shifted unsorted array 
            const mid = Math.floor((left + right) / 2); 
            
            if (nums[mid] > nums[right]) left = mid + 1; 
            //If midpoint is larger than last element, look right
            
            else right = mid; //Else look left 
      }
    

    迭代 1: 左 = 0 ,右 = 4 -> 中 = 2

    现在左边应该是 mid + 1,因为较低的值在右边。在您发言时,这不会导致超出索引错误。

    迭代 2: 左 = 3,右 = 4 -> 中 = 3

    现在右边变成了中间为 nums[mid]

    因此,返回 nums[left] = nums[3] = 1

    【讨论】:

      【解决方案2】:

      如果您将旋转后的数组可视化,例如 [6,7,8,9,1,2,3,4,5],您会得到以下模式:

                  9
               8
            7
         6
                                  5
                               4
                            3
                         2
                      1
      
         left         k           right
      

      1 是要找到的最小值,它位于索引 k 处。一旦有了索引mid,就有两种可能:

      • mid &gt;= k:我们可以看到在那种情况下,只有这样,a[mid] &lt;= a[right]
      • mid &lt; k:我们可以看到在那种情况下,只有这样,a[mid] &gt; a[right]

      在第一种情况下,mid 右侧的所有元素都可以忽略,因此我们设置了right = mid(最小值仍然可以是at mid)。

      在第二种情况下,可以忽略mid 左侧的所有元素,包括mid 本身的元素,因此我们可以设置left = mid + 1

      每次调整leftright 时,k 将保持在leftright 之间的缩小范围内,因此我们以相同的逻辑重复相同的模式。

      【讨论】:

      • 非常感谢。只是想确认一下,如果数组旋转,这是否意味着结果数组的右侧总是更小?另外,在你上面的例子中。在二分搜索的第一遍之后,我假设逻辑是设置 left = mid 因为我们知道我们需要查看数组的右侧?
      • 只需旋转一个数组,看看会发生什么。除非它完全排序,否则旋转数组的最后一个元素将按照正常排序顺序出现在数组中的第一个值之前。只需将数组旋转几次并观察......当你继续这样做时,逻辑就会出现。
      • 设置left 还是right 取决于您在if 条件中找到的内容。这就是我试图解释的。您提供的代码很好。
      • 我所做的“绘图”应该清楚地说明数组的右侧部分是如何真正属于 之前 如果您要对其进行排序的左侧部分,所以是的,这显然意味着那些右边的值比左边的值小。
      猜你喜欢
      • 2019-03-31
      • 2021-04-14
      • 1970-01-01
      • 2020-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多