LeetCode HOT100 - 搜索旋转排序数组

我觉得挺有意思的一题,对于二分的理解应当是有帮助的

首先,二分的核心在于有序

我们通过中间点 mid 和 target 的大小关系可以知道它的一侧和 target 的关系

比如 mid 比 target 小,那么 mid 左侧的元素一定都比 target 小,进而我们只需要看右侧就可以了

现在回到这题

这题就是在于单调性的分成了两段

但是我们可以知道较大一段始终是在前面的

考虑现在 mid 比 target 大的情况,按照之前的说法来说就是 r = m ,缩小右边界

但因为我们是分开的,我们不能保证 target 会不会在可能的 mid 右侧的较小段

这时候,如果 target > a[r] , 那么就相当于较小段中一定不会有 target ,进而达到了"知道 mid 的一侧和 target 的关系"的目的,于是这种情况,右侧一定不可能,r = m

else 呢, target < a[r] 但是 mid 又 > target ,这实际上已经说明了 target 是在 mid 右侧的那个较小段中,这也说明了右侧是不单调的

但是,这同时说明了 target 不会在现在的 mid 中了

所以如果现在 target 在较小段中了,那么这就是有序的情形,按照一般二分的写法就可以,否则,我们就要让左边界到达较小段

如何判断是否在较小段中呢

显然,只要和当前 mid 判断就可以了,如果 mid 小于 a[r] 了,说明就是在较小段中了,正常更新,否则不在,那么就是 l = m + 1

我这里二分写的是左闭右开的形式,也就是 l 左侧一定不可行,r 及右侧一定可行

最终退出是 l == r

class Solution {
public:
    int search(vector<int>& a, int target) {
        int n = a.size();
        int l = 0, r = n;
        while (l < r) {
            int m = (l + r) >> 1;
            cout << l << ' ' << r << ' ' << m << '\n';
            if (a[m] == target) {
                return m;
            }
            if (a[m] < target) {
                if (target < a[l]) {
                    l = m + 1;
                } else if (a[m] < a[l]) {
                    r = m;
                } else {
                    l = m + 1;
                }
            } else if (target > a[r - 1]) {
                r = m;
            } else if (a[m] > a[r - 1]) {
                l = m + 1;
            } else {
                r = m;
            }
        }
        cout << l << ' ' << r << '\n';
        return l == n ? -1 : a[l] == target ? l : -1;
    }
};

顺便回忆下二分的两种写法:

while (lo < hi) {
  int u = (lo + hi + 1) / 2;  // 上取整
  if(x >= 1ll * u * (n + n - u + 1) / 2) {
	lo = u;    // 满足条件时保留中点
  } else {
	hi = u - 1;  // 不满足时缩小右边界
  }
}

采用的是上取整,因此得到的是最后一个满足条件的位置,此时左端点是开区间

while (lo < hi) {
  int u = (lo + hi) >> 1;   // 下取整
  if(condition) {
	hi = u;    // 满足条件时缩小右边界
  } else {
	lo = u + 1;  // 不满足时增大左边界
  }
}

采用的是下取整,因此得到的是第一个满足条件的位置,此时右端点是开区间

看满足条件的最后一个位置的时候,可以看作是下面那个常见情况的反方向,这时候 lo , hi 相反,中位数要向 hi 靠近,因此需要是上取整

posted @ 2026-04-14 00:59  rdcamelot  阅读(19)  评论(0)    收藏  举报