Just focus on (left+right+1)/2
and (left+right)/2
.
mid = (left + right) / 2
to find first element valid
mid = (left + right + 1) / 2
to find last element valid
E.g. [0, 1, 1, 1, 1]
mid = (left + right) / 2
would give index 1
mid = (left + right + 1) / 2
would give index 5
For mid = (left + right + 1) / 2
: if sum == k
, since we are going to find the last valid one, then move left
till the very right: i.e. move left
;
If one wonders it's sum >= k
or sum > k
, just take a moment think about if you want to first or last same element.
Then answer would be:
class Solution {
public int maximumCandies(int[] candies, long k) {
int left = 0, right = 10000000;
while (left < right) {
int mid = (left + right + 1) / 2;
if (sum(candies, mid) >= k)
left = mid;
else
right = mid - 1;
}
return left;
}
private long sum(int[] candies, int mid) {
long count = 0;
for (int c : candies) {
count += c / mid;
}
return count;
}
}
Or, just go with the usual way
Usually we write mid = (left + right) / 2
in
if (num[mid] < target) left = mid + 1
else right = mid
This stays the same, except that return right - 1
instead of return left
:
this can be:
class Solution {
public:
int maximumCandies(vector<int>& a, long long k) {
int lo = 1, hi = *max_element(a.begin(), a.end()) + 1;
while (lo < hi) {
int mi = (lo + hi) / 2;
long long x = 0;
for (int i: a) {
x += i / mi;
}
if (x >= k) {
lo = mi + 1;
} else {
hi = mi;
}
}
return hi - 1;
}
};
The latter C++ code is from watashi. I would go with this one cuz only return value is changed.
Added:
Find K Closest Elements
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int left = 0, right = arr.length - k;
while (left < right) {
int mid = (left + right) / 2;
if (x - arr[mid] > arr[mid + k] - x)
left = mid + 1;
else
right = mid;
}
List<Integer> res = new ArrayList<>();
for (int i = left; i < left + k; ++i) {
res.add(arr[i]);
}
return res;
}
}
Takeaway: find left
(to left + k
) whose mid
would be closest to x
Also good:
Some propose a binary search for closestIndex
, then a diffusion two pointers for the range.
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
// find the closest element and expand the range
int closestIdx = 0;
int i = 0;
int j = arr.length - 1;
while(i < j - 1){
int mid = i + (j - i)/2;
if(arr[mid] > x) j = mid;
else i = mid;
}
// post-processing
closestIdx = Math.abs(arr[i] - x) <= Math.abs(arr[j] - x) ? i : j;
List<Integer> list = new ArrayList<>();
int count = 1;
i = closestIdx - 1;
j = closestIdx + 1;
while(count < k){
if(i < 0) j++;
else if(j >= arr.length) i--;
else if(Math.abs(arr[i] - x) <= Math.abs(arr[j] - x)) i--;
else j++;
count++;
}
for(int m = i + 1; m <= j - 1; m++) list.add(arr[m]);
return list;
}
}