二分法的模版:

类似双指针的操作。

  1. var test = function(nums) {
  2. let n = nums.length;
  3. let l = 0;
  4. let r = n - 1;
  5. let m = -1; // -1 代表不指向数组里任何一个位置
  6. while (l <= r) {
  7. m = l + Math.floor((r - l) / 2);
  8. if ('has found') {
  9. return m;
  10. }
  11. if ('condition1') {
  12. l = m + 1;
  13. continue;
  14. }
  15. if ('condition2') {
  16. r = m;
  17. continue;
  18. }
  19. }
  20. return -1;
  21. }

367. 有效的完全平方数

但是寻找平方根呢,还有暴力解法:(效果也不差,但是是一点一点去找,比较麻烦)

  1. var isPerfectSquare = function(num) {
  2. if (num <= 1) {
  3. return true;
  4. }
  5. for (let i = 0; i * i <= num; i++) {
  6. if (i * i === num) {
  7. return true;
  8. }
  9. }
  10. return false;
  11. };

以下这个二分法提效,从写法上来说也是双指针:

  1. var isPerfectSquare = function(num) {
  2. let l = 0;
  3. let r = num;
  4. while (l <= r) {
  5. let m = l + Math.floor((r - l) / 2);
  6. let square = m * m;
  7. if (num === square) {
  8. return true;
  9. } else if (num < square) {
  10. r = m - 1;
  11. } else {
  12. l = m + 1;
  13. }
  14. }
  15. return false;
  16. };

162. 寻找峰值

这个题的前提,数组之间相邻元素不相同。
不是 和 左右边界比,而是和 相邻左右比较。 ==》 找一种条件可以 二分的形式缩小解的范围

  1. var findPeakElement = function(nums) {
  2. let n = nums.length;
  3. let l = 0;
  4. let r = n - 1;
  5. let m = -1; // -1 代表不指向数组里任何一个位置
  6. while (l <= r) {
  7. m = l + Math.floor((r - l) / 2);
  8. // 边界处理很帅呀
  9. let left = (m === 0) ? -Infinity : nums[m - 1];
  10. let right = (m === n - 1) ? -Infinity : nums[m + 1];
  11. if (left < nums[m] && nums[m] > right) {
  12. return m;
  13. }
  14. if (nums[m] < right) {
  15. l = m + 1;
  16. continue;
  17. }
  18. if (nums[m] < left) {
  19. r = m; // 保留最大值
  20. // r = m - 1;
  21. continue;
  22. }
  23. }
  24. return -1;
  25. }

33. 搜索旋转排序数组

image.png
老大哥我费了大力气,终于解出来了,我的思考:就是在找的过程丢掉尽可能多的地方,有效缩小搜索范围。

  1. var search = function(nums, target) {
  2. let n = nums.length;
  3. if (n === 0) {
  4. return -1;
  5. }
  6. if (n === 1) {
  7. return nums[0] === target ? 0 : -1;
  8. }
  9. // 1、先去找转折点
  10. let l = 0;
  11. let r = n - 1;
  12. let m = -1; // -1 代表不指向数组里任何一个位置
  13. while (l <= r) {
  14. m = l + Math.floor((r - l) / 2);
  15. if (nums[m] === target) {
  16. return m;
  17. }
  18. if (nums[l] <= nums[m]) { // 隔出有序区间[l...m]
  19. if (nums[l] <= target && target < nums[m]) { // 在 有序区间[l...m] 中
  20. r = m - 1;
  21. } else {
  22. l = m + 1;
  23. }
  24. } else { // 隔出有序区间[m...r]
  25. if (nums[m] < target && target <= nums[r]) { // 在 有序区间[m...r] 中
  26. l = m + 1;
  27. } else {
  28. r = m - 1;
  29. }
  30. }
  31. }
  32. return -1;
  33. };

74. 搜索二维矩阵

// 加强版 二分搜索