Skip to content

Commit af7efee

Browse files
committed
EPI: closest_int_same_weight
1 parent e79e038 commit af7efee

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

elements-of-programming-interviews/cpp/closest_int_same_weight.cc

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,75 @@
11
#include "test_framework/generic_test.h"
2+
3+
void printBin(unsigned long long val, size_t len, const std::string& suffix) {
4+
std::string binval;
5+
for (size_t i = 0; i < len; i++) {
6+
binval.append(val & 1 ? "1" : "0");
7+
val >>= 1;
8+
}
9+
reverse(binval.begin(), binval.end());
10+
printf("%s (%s)\n", binval.c_str(), suffix.c_str());
11+
}
12+
13+
bool sameWeight(unsigned long long left, unsigned long long right) {
14+
int leftWeight = 0;
15+
int rightWeight = 0;
16+
while (left > 0 || right > 0) {
17+
if (left & 1) {
18+
leftWeight++;
19+
}
20+
left >>= 1;
21+
if (right & 1) {
22+
rightWeight++;
23+
}
24+
right >>= 1;
25+
}
26+
return rightWeight == leftWeight;
27+
}
28+
29+
unsigned long long ClosestIntSameBitCountBruteForce(unsigned long long x) {
30+
/*
31+
Approach 1: look for the best weight explicitly knowing the value
32+
If we have a constant time approach for measuring the weight of a number,
33+
we could just try repeatedly calculating x++ and x-- until we find a value
34+
of the same weight. This is a brute force approach that technically works
35+
here but can become quite inefficient.
36+
*/
37+
unsigned long long nearestUp = x + 1;
38+
unsigned long long nearestDown = x - 1;
39+
40+
while (true) {
41+
if (sameWeight(x, nearestUp)) {
42+
return nearestUp;
43+
}
44+
if (sameWeight(x, nearestDown)) {
45+
return nearestDown;
46+
}
47+
nearestUp++;
48+
nearestDown--;
49+
}
50+
}
51+
252
unsigned long long ClosestIntSameBitCount(unsigned long long x) {
3-
// TODO - you fill in here.
4-
return 0;
53+
/*
54+
Approach 2: look for the best value by explicitly knowing the weight
55+
To create y, we need to unset one bit in x, and set one unset bit in x.
56+
Unsetting is subtracting, and setting is adding. We want the net change
57+
between y and x to be as small as possible, so we want these two bits to be as
58+
close as possible. If we flip the first set bit we find, then the optimal
59+
choice is to flip the first unset bit to its right; this may not exist though.
60+
Consider 0xff, 255. Although changing this to 0xfe = 254 subtracts the
61+
smallest amount possible, the difference after we set a new bit will be huge,
62+
e.g. 0x1fe = 510. So what we want is to flip two differing bits that are as
63+
close as possible, i.e. adjacent. The book phrases this as "look for the
64+
least significant pair of differing bits and swap them".
65+
*/
66+
int i = 1, j = 0;
67+
while (((x >> i) & 1) == ((x >> j) & 1)) {
68+
i++;
69+
j++;
70+
}
71+
int mask = (1LL << i) | (1LL << j);
72+
return x ^ mask;
573
}
674

775
int main(int argc, char* argv[]) {

elements-of-programming-interviews/problem_mapping.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ problem_mapping = {
5858
},
5959
"4.04 Find a closest integer with the same weight": {
6060
"C++: closest_int_same_weight.cc": {
61-
"passed": 0,
61+
"passed": 10000,
6262
"total": 10000
6363
},
6464
"Java: ClosestIntSameWeight.java": {

0 commit comments

Comments
 (0)