binary search

2021-07-05
  • Basic template: stt + 1; stt + (fin - stt)/2; get result from stt and fin.
  • 理论:二分查找,通过二分查找,trie,KMP,哈希表来进行;遍历排序,heap,quick sort;数组类型的就是前缀后缀,以及单调栈全部过一遍。
// Choose the interval [] containing the answer.
// Integer binary search.
// Template 1.
int binarySearch(const vector<int> &A, const int target) {
  if (A.empty() {
    return -1;
  }
  int start = 0;
  int end = A.size() - 1;
  int mid;

  while (start + 1 < end) {
    mid = start + (end - start) / 2;
    if (A[mid] == target) {
      end = mid;
    } else if (A[mid] < target) {
      start = mid;
    } else if (A[mid] > target) {
      end = mid;
    }
  }

  // judge which side you want.    
  if (A[start] == target) {
    return start;
  }
  if (A[end] == target) {
    return end;
  }

  return -1; 
}
// Template 2.
      
// 704. Binary Search 
int search(vector<int>& nums, int target) { 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  int mid_idx; 
  while (stt_idx + 1 < fin_idx) { 
    mid_idx = stt_idx + (fin_idx - stt_idx)/2; 
    if (nums[mid_idx] < target) stt_idx = mid_idx; 
    else if (nums[mid_idx] >= target) fin_idx = mid_idx; 
  } 
  if (nums[stt_idx] == target) return stt_idx; 
  if (nums[fin_idx] == target) return fin_idx; 
  return -1; 
} 
 
// 278. First Bad Version 
int firstBadVersion(int n) { 
  int stt_idx = 1; 
  int fin_idx = n; 
  while (stt_idx + 1 < fin_idx) { 
    int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    if (isBadVersion(mid_idx)) fin_idx = mid_idx; 
    else stt_idx = mid_idx; 
  } 
  if (isBadVersion(stt_idx)) return stt_idx; 
  if (isBadVersion(fin_idx)) return fin_idx; 
  return -1; 
} 
  • 1755 Closest Subsequence Sum
void GetSum(const vector<int>& nums, const int target, const int idx, 
            const int cur, unordered_set<int>& s) {
  if (idx > target) {
    s.insert(cur);
    return;
  }
  GetSum(nums, target, idx+1, cur, s);
  GetSum(nums, target, idx+1, cur + nums[idx], s);
}
  
int minAbsDifference(vector<int>& nums, int goal) {
  unordered_set<int> sum1;
  unordered_set<int> sum2;  
  GetSum(nums, nums.size()/2, 0, 0, sum1);
  GetSum(nums, nums.size() - 1, nums.size()/2+1, 0, sum2);  
  vector<int> half_vec(sum1.begin(), sum1.end());
  sort(half_vec.begin(), half_vec.end());  
  int min_val = INT_MAX;
  for (const auto& num : sum2) {
    int idx = lower_bound(half_vec.begin(), half_vec.end(), 
                          goal - num) - half_vec.begin(); 
    if (idx < half_vec.size()) 
      min_val = min(min_val, abs(goal - half_vec[idx] - num));
    if (idx > 0)
      min_val = min(min_val, abs(goal - half_vec[idx-1] - num));
  }
  return min_val;
}
  • Search for the minmax and maxmin
// 1760 Minimum Limit of Balls in a Bag
// Solution: https://leetcode-cn.com/problems/minimum-limit-of-balls-in-a-bag/solution/dai-zi-li-zui-shao-shu-mu-de-qiu-by-zero-upwe/
// Looking for left BS framework
/*
L = 最小的可能值;
R = 最大的可能值;
while (L < R)
{
    mid = (L + R) >> 1;
    if (检查发现,mid是ok的)
        R = mid;
    else
        L = mid + 1;
}
return L;
*/

int minimumSize(vector<int>& nums, int maxOperations) {
  int left = 1;
  int right = 1e9;
  int mid;
  while (left + 1 < right) {
    mid = left + (right - left) / 2;
    int cur = 0;
    for (const auto& num : nums) {
      cur += ceil((num*1.0)/mid) - 1;
    }
    // cout << cur << " " << mid << endl;
    if (cur <= maxOperations) {
      right = mid;
    } else if (cur > maxOperations) {
      left = mid;
    }
  }
  int cur = 0;
  for (const auto& num : nums) {
    cur += ceil((num*1.0)/left) - 1;
  }
  if (cur < maxOperations) return left;
  return right;
}

int minimumSize(vector<int>& nums, int maxOperations) {
  int left = 1;
  int right = 1e9;
  int mid;
  while (left < right) {
    mid = left + (right - left) / 2;
    int cur = 0;
    for (const auto& num : nums) {
      cur += ceil((num*1.0)/mid) - 1;
    }
    if (cur > maxOperations) {
      left = mid + 1;
    } else {
      right = mid;
    }
  }
  return left;
}

// 1552 Magnetic force between two balls
int Check(const vector<int>& position, const int m, const int dis) {
  int idx = 0;
  int cnt = 1;
  int stt = 0;
  while (idx < position.size()) {
    if (position[idx] - position[stt] >= dis) {
      ++cnt;
      stt = idx;
    } else {
      ++idx;
    }
  }
  return cnt >= m?-1:0;
}
  
int maxDistance(vector<int>& position, int m) {
  int left = 1;
  int right = 1e9;
  int mid;
  sort(begin(position), end(position));
  while (left + 1 < right) {
    mid = left + (right - left) / 2;
    if (Check(position, m, mid) < 0) {
      left = mid;
    } else {
      right = mid;
    }
  }
  return left;
}
  • Search for range
// 34. Find First and Last Position of Element in Sorted Array 
int BinarySearch(vector<int>& nums, int target, bool status) { 
  if (!nums.size()) return -1; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  int mid = -1; 
  while (stt_idx + 1 < fin_idx) { 
    mid = stt_idx + (fin_idx - stt_idx) / 2; 
    if (nums[mid] > target) fin_idx = mid; 
    else if (nums[mid] < target) stt_idx = mid; 
    else if (!status) fin_idx = mid; 
    else stt_idx = mid; 
  } 
  bool stt_status = nums[stt_idx] == target; 
  bool fin_status = nums[fin_idx] == target; 
  if (!status) { 
    if (stt_status) return stt_idx; 
    if (fin_status) return fin_idx;   
  } else { 
    if (fin_status) return fin_idx; 
    if (stt_status) return stt_idx; 
  } 
  return -1; 
} 

vector<int> searchRange(vector<int>& nums, int target) { 
  int left_idx = BinarySearch(nums, target, 0); 
  int right_idx = BinarySearch(nums, target, 1); 
  return {left_idx, right_idx}; 
} 
  • Search for positions
// 35. Search Insert Position 
int searchInsert(vector<int>& nums, int target) { 
  if (!nums.size()) return 0; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    int mid = stt_idx + (fin_idx - stt_idx) / 2; 
    if (nums[mid] < target) stt_idx = mid; 
    else fin_idx = mid; 
  } 
  if (nums[stt_idx] == target) return stt_idx; 
  if (nums[fin_idx] == target) return fin_idx; 
  if (nums[stt_idx] > target) return stt_idx; 
  else if (nums[fin_idx] < target) return fin_idx + 1; 
  else return stt_idx + 1; 
} 
  • Search in matrix
// 240. Search a 2D Matrix II 
bool searchMatrix(vector<vector<int>>& matrix, int target) { 
  int rows = matrix.size(); 
  int cols = !rows?0:matrix[0].size(); 
  if (!rows || !cols) return false; 
  pair<int, int> search_idx(rows - 1, 0); 
  while (search_idx.first >= 0 && search_idx.second < cols) { 
    const auto [row_idx, col_idx] = search_idx; 
    const auto cur_val = matrix[row_idx][col_idx]; 
    if (cur_val > target) --search_idx.first; 
    else if (cur_val < target) ++search_idx.second; 
    else return true; 
  } 
  return false; 
} 

// 74. Search a 2D Matrix 
pair<int, int> BinarySearch(vector<int>& nums, int target) { 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    const auto val = nums[mid_idx]; 
    if (val < target) stt_idx = mid_idx; 
    else if (val >= target) fin_idx = mid_idx; 
  } 
  if (nums[stt_idx] == target || nums[fin_idx] == target) return {0, true}; 
  if (nums[stt_idx] > target) return {-1, false}; 
  if (nums[fin_idx] < target) return {fin_idx, false}; 
  return {stt_idx, false}; 
} 

bool searchMatrix(vector<vector<int>>& matrix, int target) { 
  int rows = matrix.size(); 
  int cols = !rows?0:matrix[0].size(); 
  if (!rows || !cols) return false; 
  vector<int> column_data; 
  for (int idx = 0; idx < rows; ++idx) column_data.emplace_back(matrix[idx][0]); 
  const auto [col_idx, status_1] = BinarySearch(column_data, target); 
  if (status_1) return true; 
  if (col_idx == -1) return false; 
  const auto [row_idx, status_2] = BinarySearch(matrix[col_idx], target); 
  return status_2; 
} 
  • Rotated array search
// 33. Search in Rotated Sorted Array 
int search(vector<int>& nums, int target) { 
  if (!nums.size()) return -1; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    const int val = nums[mid_idx]; 
    if (nums[stt_idx] < val) { 
      if (val >= target && nums[stt_idx] <= target) fin_idx = mid_idx; 
      else stt_idx = mid_idx; 
    } else { 
      if (val <= target && nums[fin_idx] >= target) stt_idx = mid_idx; 
      else fin_idx = mid_idx; 
    } 
  } 
  if (nums[stt_idx] == target) return stt_idx; 
  if (nums[fin_idx] == target) return fin_idx; 
  return -1; 
} 

// 81. Search in Rotated Sorted Array II 
bool search(vector<int>& nums, int target) { 
  if (!nums.size()) return false; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    const int val = nums[mid_idx]; 
    if (nums[stt_idx] < val) { 
      if (val >= target && nums[stt_idx] <= target) fin_idx = mid_idx; 
      else stt_idx = mid_idx; 
    } else if (nums[stt_idx] > val){ 
      if (val <= target && nums[fin_idx] >= target) stt_idx = mid_idx; 
      else fin_idx = mid_idx; 
    } else { 
      ++stt_idx; 
    }        
  } 
  if (nums[stt_idx] == target || nums[fin_idx] == target) return true; 
  return false;   
}  
  • Find minimum in rotated array
// 153. Find Minimum in Rotated Sorted Array 
int findMin(vector<int>& nums) { 
  if (!nums.size()) return -1; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    const int val = nums[mid_idx]; 
    const int stt_val = nums[stt_idx]; 
    const int fin_val = nums[fin_idx]; 
    if (val > stt_val) { 
      if (stt_val > fin_val) stt_idx = mid_idx; 
      else fin_idx = mid_idx; 
    } else { 
      fin_idx = mid_idx; 
    } 
  } 
  return nums[stt_idx] < nums[fin_idx] ? nums[stt_idx]:nums[fin_idx]; 
} 

// 154. Find Minimum in Rotated Sorted Array II 
int findMin(vector<int>& nums) { 
  if (!nums.size()) return -1; 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    const int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    const int val = nums[mid_idx]; 
    const int stt_val = nums[stt_idx]; 
    const int fin_val = nums[fin_idx]; 
    if (val >= stt_val) { 
      if (stt_val < fin_val) fin_idx = mid_idx; 
      else if (stt_val > fin_val) stt_idx = mid_idx; 
      else ++stt_idx; 
    } else { 
      if (stt_val > fin_val) fin_idx = mid_idx; 
      else ++stt_idx; 
    } 
  } 
  return nums[stt_idx] < nums[fin_idx] ? nums[stt_idx] : nums[fin_idx]; 
} 

// 88. Merge Sorted Array 
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { 
  for (int idx = m - 1; idx >= 0; --idx) nums1[n+idx] = nums1[idx]; 
  int stt_1 = n; 
  int stt_2 = 0; 
  int cur = 0; 
  while (stt_2 < n && stt_1 < m+n) { 
    if (nums1[stt_1] <= nums2[stt_2]) nums1[cur++] = nums1[stt_1++];   
    else nums1[cur++] = nums2[stt_2++]; 
  } 
  if (stt_2 < n) { 
    for (int i = cur; i < n + m; ++i) nums1[i] = nums2[stt_2++]; 
  } 
} 
  • 3 Steps Reverse
// 796. Rotate String 
// method 1 
bool rotateString(string A, string B) { 
  const string A2 = A + A; 
  return A2.find(B) != -1 && A.size() == B.size(); 
} 

// method 2 
void ReverseString(string& str, int stt_idx, int fin_idx) { 
  while (stt_idx < fin_idx) { 
    swap(str[stt_idx++], str[fin_idx--]); 
  } 
}   

bool rotateString(string A, string B) { 
  if (A.size() != B.size()) return false; 
  for (int i = 0; i < A.size() - 1; ++i) { 
    string tmp = B; 
    ReverseString(tmp, 0, i); 
    ReverseString(tmp, i+1, B.size() - 1); 
    ReverseString(tmp, 0, B.size() - 1); 
    if (tmp == A) return true; 
  } 
  return false; 
} 

// 151. Reverse Words in a String 
void ReverseString(string& str, int stt_idx, int fin_idx) { 
  while (stt_idx < fin_idx) { 
    swap(str[stt_idx++], str[fin_idx--]); 
  } 
} 

string StripString(string str) { 
  int stt_idx = 0; 
  while (stt_idx < str.size() && str[stt_idx] == ' ') ++stt_idx; 
  int fin_idx = str.size() - 1; 
  while (fin_idx >= 0 && str[fin_idx] == ' ') --fin_idx; 
  string s = str.substr(stt_idx, fin_idx - stt_idx + 1); 
  string fin_s; 
  bool has_empty = false; 
  for (const auto c:s) { 
    if (c == ' ') { 
      if (has_empty) continue; 
      has_empty = true; 
      fin_s += c; 
    } else { 
      has_empty = false; 
      fin_s += c; 
    } 
  } 
  return fin_s; 
} 

string reverseWords(string s) { 
  s = StripString(s); 
  int s_len = s.size(); 
  int stt_idx = -1; 
  for (int idx = 0; idx < s_len; ++idx) { 
    if (s[idx] == ' ') { 
      if (stt_idx != -1) 
        ReverseString(s, stt_idx, idx - 1); 
      stt_idx = -1; 
    } else if (stt_idx == -1) stt_idx = idx; 
  } 
  if (stt_idx != -1) 
    ReverseString(s, stt_idx, s_len - 1); 
  ReverseString(s, 0, s_len - 1); 
  return s; 
} 

// 186. Reverse Words in a String II 
void ReverseString(vector<char>& s, int stt_idx, int fin_idx) { 
  while (stt_idx < fin_idx) { 
    swap(s[stt_idx++], s[fin_idx--]); 
  } 
} 

void reverseWords(vector<char>& s) { 
  int s_len = s.size(); 
  int stt_idx = -1; 
  for (int idx = 0; idx < s_len; ++idx) { 
    if (s[idx] == ' ') { 
      if (stt_idx != -1) ReverseString(s, stt_idx, idx - 1); 
      stt_idx = -1; 
    } else { 
      if (stt_idx == -1) stt_idx = idx; 
    } 
  } 
  if (stt_idx != -1) ReverseString(s, stt_idx, s_len - 1); 
  ReverseString(s, 0, s_len - 1); 
} 

// 557. Reverse Words in a String III 
void ReverseString(string& str, int stt_idx, int fin_idx) { 
  while (stt_idx < fin_idx) { 
    swap(str[stt_idx++], str[fin_idx--]); 
  }  
} 

string reverseWords(string s) { 
  int s_len = s.size(); 
  int stt_idx = -1; 
  for (int idx = 0; idx < s_len; ++idx) { 
    if (s[idx] == ' ') { 
      if (stt_idx != -1) ReverseString(s, stt_idx, idx - 1); 
      stt_idx = -1; 
    } else if (stt_idx == -1){ 
      stt_idx = idx; 
    } 
  } 
  if (stt_idx != -1) 
    ReverseString(s, stt_idx, s_len - 1); 
  return s; 
} 

// 26. Remove Duplicates from Sorted Array 
int removeDuplicates(vector<int>& nums) { 
  int cur_idx = 0; 
  int pre_idx = 0; 
  int nums_len = nums.size(); 
  while (cur_idx < nums_len) { 
    while (cur_idx + 1 < nums_len) { 
      if (nums[cur_idx] == nums[cur_idx + 1]) { 
        ++cur_idx; 
      } else break; 
    } 
    nums[pre_idx] = nums[cur_idx]; 
    ++pre_idx; 
    ++cur_idx; 
  } 
  return !nums_len?0:pre_idx; 
} 
  • Find a peak
// 162. Find Peak Element 
int findPeakElement(vector<int>& nums) { 
  int stt_idx = 0; 
  int fin_idx = nums.size() - 1; 
  while (stt_idx + 1 < fin_idx) { 
    int mid_idx = stt_idx + (fin_idx - stt_idx) / 2; 
    if (nums[mid_idx] < nums[mid_idx+1]) stt_idx = mid_idx; 
    else if (nums[mid_idx] < nums[mid_idx-1]) fin_idx = mid_idx; 
    else return mid_idx; 
  } 
  return nums[fin_idx] > nums[stt_idx]?fin_idx:stt_idx; 
} 
  • Median of two sorted arrays
// 4. Median of Two Sorted Arrays 
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { 
  int len1 = nums1.size(); 
  int len2 = nums2.size(); 
  int len = len1 + len2; 
  if (!len) return 0; 
 return len&1 ?  
        MedianSortedArray(nums1, nums2, len/2 + 1): 
        (MedianSortedArray(nums1, nums2, len/2 + 1) +  
         MedianSortedArray(nums1, nums2, len/2)) * 0.5; 
} 

double MedianSortedArray(vector<int>& nums1, vector<int>& nums2, int k) { 
  int stt_1 = 0; 
  int stt_2 = 0; 
  while (k > 1) { 
    int idx_1 = stt_1 + k / 2 - 1; 
    int val_1 = idx_1 >= nums1.size()?INT_MAX:nums1[idx_1]; 
    int idx_2 = stt_2 + k / 2 - 1; 
    int val_2 = idx_2 >= nums2.size()?INT_MAX:nums2[idx_2]; 
    if (val_1 <= val_2) stt_1 += k/2; 
    else stt_2 += k/2; 
    k -= k/2; 
  } 
  if (stt_1 >= nums1.size()) return nums2[stt_2]; 
  if (stt_2 >= nums2.size()) return nums1[stt_1]; 
  return nums1[stt_1] <= nums2[stt_2]?nums1[stt_1]:nums2[stt_2]; 
}