当前位置:   article > 正文

二分法的应用-C++_c++分治二分法

c++分治二分法

二分法是典型的分治算法。

我们使用二分法通常的目的是为了减小遍历规模。假如求解一个问题,本来需要遍历整个数组,得到结果。但是由于数组的特殊性问题的特殊性,我们能够排除一半的错误结果不需要遍历,这就是二分法的使用逻辑。

一般,二分法会把一个时间复杂度为O(n) 的算法缩减为复杂度O(log n)

下面使用二分法求解几个问题:

1、问题:在一个有序数组中,找某个指定数值是否存在。

解:要求解特定值,假设特定值为A。由于数组有序,我们可以先求数组的中间位置的值B,如果A>B,则说明A在B的右半侧,反正,A在左半侧。以此类推,可以找到数组中是否有A值

参考代码

  1. bool MyFun(std::vector<int>& arr,const int A)
  2. {
  3. int start = 0; //起始位置
  4. int end = arr.size()-1; //末尾位置
  5. if (A == arr[start] || A == arr[end])
  6. {
  7. return true;
  8. }
  9. //使用二分法求解
  10. while (start != end)
  11. {
  12. int mid = (start + end) / 2; //获取中间位置的数值
  13. //如果相等,则找到A
  14. if (A == arr[mid])
  15. {
  16. return true;
  17. }
  18. //如果A比较大,说明A在mid右侧
  19. else if(A > arr[mid])
  20. {
  21. if (start == mid)
  22. {
  23. break;
  24. }
  25. start = mid;
  26. }
  27. //如果A比较小,说明A在mid左侧
  28. else
  29. {
  30. if (end == mid)
  31. {
  32. break;
  33. }
  34. end = mid;
  35. }
  36. }
  37. return false;
  38. }

2、问题:在一个有序数组中,找>=某个数最左侧的位置

:首先,这个数组有序;其次,寻找某个特定的值(位置),这样很容易想到使用二分法。假设指定值为A,寻找>=A的最左侧,就是要尽量保留左半侧

  1. int MyFun(std::vector<int>& arr,const int A)
  2. {
  3. int start = 0; //起始位置
  4. int end = arr.size()-1; //末尾位置
  5. int ret = arr.size();
  6. if (arr[end] < A)
  7. {
  8. return ret;
  9. }
  10. if (arr[start] >= A)
  11. {
  12. return 0;
  13. }
  14. //使用二分法求解
  15. while (start != end)
  16. {
  17. int mid = (start + end) / 2; //获取中间位置的数值
  18. //如果mid位置>=A,则先记录mid,再丢弃右半部分,在左半侧继续寻找
  19. if (arr[mid] >= A)
  20. {
  21. ret = mid < ret ? mid : ret;
  22. if (end == mid)
  23. {
  24. break;
  25. }
  26. end = mid;
  27. //如果左半侧最大值小于A,则不需再找
  28. if (arr[end-1] < A)
  29. {
  30. break;
  31. }
  32. }
  33. //说明mid以左,都不存在不小于A的值,丢弃左半侧
  34. else
  35. {
  36. if (start == mid)
  37. {
  38. break;
  39. }
  40. start = mid;
  41. //如果左半侧最小值>=A,则不需再找
  42. if (arr[start+1] >= A)
  43. {
  44. ret = start + 1 < ret ? start + 1 : ret;
  45. break;
  46. }
  47. }
  48. }
  49. return ret;
  50. }

【注】不一定需要有序的数组才能使用二分法求解,如果问题具有特殊性,无序数组也可以使用二分法。

例如:问题3

arr是一个无序数组,且相邻2个元素一定不相等。求这个数组的一个局部最小值。

参考代码

  1. int MyFun(std::vector<int>& arr)
  2. {
  3. int start = 0;
  4. int end = arr.size() - 1;
  5. //先查看第1个元素和最后一个元素是不是局部最小值
  6. if (arr[start] < arr[start + 1])
  7. {
  8. return arr[start];
  9. }
  10. if (arr[end] < arr[end - 1])
  11. {
  12. return arr[end];
  13. }
  14. //trend1为左侧的趋势;trend2为右侧的趋势;如果升序是true;降序是false
  15. //start和end的位置都不是局部最小所在位置,说明trend1是降序,trend2是升序
  16. bool trend1 = false;
  17. bool trend2 = true;
  18. //使用二分法求解
  19. while (start != end)
  20. {
  21. int mid = (start + end) / 2;
  22. //中间位置的趋势
  23. if (mid + 1 < end)
  24. {
  25. bool tr = arr[mid] < arr[mid + 1];
  26. if (trend1 == tr)
  27. {
  28. start = mid;
  29. }
  30. else if (trend2 == tr)
  31. {
  32. end = mid + 1;
  33. }
  34. }
  35. //不用继续比较,输出结果
  36. else
  37. {
  38. return arr[mid];
  39. }
  40. }
  41. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/348883
推荐阅读
相关标签
  

闽ICP备14008679号