646 lines
30 KiB
HTML
646 lines
30 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link rel="stylesheet" href="/styles/common.css" />
|
|
<link rel="stylesheet" href="/styles/post.css" />
|
|
<link rel="icon" type="image/webp" href="/public/logo.webp" />
|
|
<link href="/public/prism/prism.css" rel="stylesheet" />
|
|
<link href="/public/prism/prism-theme.css" rel="stylesheet" />
|
|
<script defer src="/public/prism/prism.js"></script>
|
|
<script
|
|
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
|
|
async
|
|
></script>
|
|
<title>leetcode daily</title>
|
|
</head>
|
|
<body class="graph-background">
|
|
<site-header></site-header>
|
|
<main class="main">
|
|
<div class="post-container">
|
|
<header class="post-header">
|
|
<h1 class="post-title">leetcode daily</h1>
|
|
</header>
|
|
<article class="post-article">
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/count-good-numbers/submissions/1605647445/?envType=daily-question&envId=2025-04-13"
|
|
>count good numbers</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-04-13">04/13/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>understanding the problem</h3>
|
|
<p>
|
|
p is a combinatoric problem at heart. You have some slots for
|
|
evens and some for primes, with a limited number of choices for
|
|
each. Leverage the multiplication rule, which states that if you
|
|
have \(n\) slots with \(x\) choices, you get \(x^n\) possible
|
|
outcomes.
|
|
</p>
|
|
<h3>doing it</h3>
|
|
<p>
|
|
So, what's the answer? If we know which slots we have and the
|
|
number of choices for them, we're done. Since this is leetcode,
|
|
they don't let you think—they just give you the answer. You
|
|
have 2 types of slots (even and odd indices) with 5
|
|
(\(\{0,2,4,6,8\}\)) and 4 (\(\{2,3,5,7\}\)) choices respectively.
|
|
Therefore, the answer is: \(5^{\text{# even slots}}\cdot4^{\text{#
|
|
odd slots}}\) By counting or with small cases, we have
|
|
\(\lceil\frac{n}{2}\rceil\) even slots and
|
|
\(\lfloor\frac{n}{2}\rfloor\) odd slots. Let's submit it!
|
|
</p>
|
|
<p>
|
|
And.... TLE. Checking <i>everything</i> when you submit your
|
|
code—in this case, constraint \(n\leq 10^{16}\) informs us
|
|
of something suspect. In the worst case, \(\frac{n}{2}\approx
|
|
n^14\). This is far too many multiplications, so we can leverage
|
|
binary exponentiation instead (and probably should've been the
|
|
whole time!). Don't forget the mod.
|
|
</p>
|
|
<div class="code" data-file="cgn.cpp"></div>
|
|
</div>
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/minimum-number-of-operations-to-make-elements-in-array-distinc"
|
|
>minimum number of operations to make array distinct</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-04-09">04/09/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>understanding the problem</h3>
|
|
<p>
|
|
You can remove elements in groups of 3 <i>solely</i> from the
|
|
beginning of the array. Perform this operation until there are no
|
|
more duplicates left, returning the number of times you had to
|
|
perform the operation.
|
|
</p>
|
|
<h3>solution: rephrase the question</h3>
|
|
<p>
|
|
Definitionally, you remove the <i>last</i> duplicate. If such
|
|
duplicate is at 0-indexed <code>i</code>, it belongs to the
|
|
\(\lceil \frac{i + 1}{3}\rceil\)th chunk of 3 (i.e. operation).
|
|
Find the last duplicate by leveraging a frequency map and
|
|
iterating backwards through the input.
|
|
</p>
|
|
<div class="code" data-file="mnootmad.cpp"></div>
|
|
<h3>asymptotic complexity</h3>
|
|
<p>
|
|
The solution is optimal, considering the least amount of elements
|
|
possible in:
|
|
</p>
|
|
<ul>
|
|
<li><u>Time Complexity</u>: \(\O(n)\)</li>
|
|
<li><u>Space Complexity</u>: \(\Theta(1)\)</li>
|
|
</ul>
|
|
</div>
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/count-the-number-of-fair-pairs/"
|
|
>count the number of fair pairs</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-09-13">09/13/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>problem statement</h3>
|
|
<p>
|
|
Given an array <code>nums</code> of integers and upper/lower
|
|
integer bounds <code>upper</code>/<code>lower</code> respectively,
|
|
return the number of unique valid index pairs such that: \[i\neq
|
|
j,lower\leq nums[i]+nums[j]\leq upper\]
|
|
</p>
|
|
<h3>understanding the problem</h3>
|
|
<p>
|
|
This is another sleeper daily in which a bit of thinking in the
|
|
beginning pays dividends. Intuitively, I think it makes sense to
|
|
reduce the “dimensionality” of the problem. Choosing
|
|
both <code>i</code> and <code>j</code> concurrently seems tricky,
|
|
so let's assume we've found a valid <code>i</code>. What
|
|
must be true? Well: \[i\neq j,lower-nums[i]\leq nums[j]\leq
|
|
upper-nums[i]\]
|
|
</p>
|
|
<p>
|
|
It doesn't seem like we've made much progress. If nums
|
|
is a sequence of random integers,
|
|
<i
|
|
>there's truly no way to find all <code>j</code> satisfying
|
|
this condition efficiently</i
|
|
>.
|
|
</p>
|
|
<p>
|
|
The following question naturally arises: can we modify our input
|
|
to find such <code>j</code> efficiently? Recall our goal: find the
|
|
smallest/largest j to fit within our altered bounds—in other
|
|
words, find the smallest \(x\) less/greater than or equal to a
|
|
number. If binary search bells aren't clanging in your head
|
|
right now, I'm not sure what to say besides keep practicing.
|
|
</p>
|
|
<p>
|
|
So, it would be nice to sort <code>nums</code> to find such
|
|
<code>j</code> relatively quickly. However:
|
|
<i>are we actually allowed to do this?</i> This is the core
|
|
question I think everyone skips over. Maybe it is trivial but it
|
|
is important to emphasize:
|
|
</p>
|
|
<ul style="list-style: none">
|
|
<li>
|
|
<i>Yes, we are allowed to sort the input</i>. Re-frame the
|
|
problem: what we are actually doing is choosing distinct
|
|
<code>i</code>, <code>j</code> to satisfy some condition. The
|
|
order of <code>nums</code> does not matter—rather, its
|
|
contents do. Any input to this algorithm with
|
|
<code>nums</code> with the same contents will yield the same
|
|
result. If we were to modify <code>nums</code> instead of
|
|
rearrange it, this would be invalid because we could be
|
|
introducing/taking away valid index combinations.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
Let's consider our solution a bit more before implementing
|
|
it:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
Is the approach feasible? We're sorting
|
|
<code>nums</code> then binary searching over it considering all
|
|
<code>i</code>, which will take around \(O(nlg(n))\) time.
|
|
<code>len(nums)</code>\(\leq10^5\), so this is fine.
|
|
</li>
|
|
<li>
|
|
How do we avoid double-counting? The logic so far makes no
|
|
effort. If we consider making all pairs with indices
|
|
<i>less than</i> <code>i</code> for all
|
|
<code>i</code> left-to-right, we'll be considering all
|
|
valid pairs with no overlap. This is a common pattern—take
|
|
a moment to justify it to yourself.
|
|
</li>
|
|
<li>
|
|
<i>Exactly</i> how many elements do we count? Okay, we're
|
|
considering some rightmost index <code>i</code> and we've
|
|
found upper and lower index bounds <code>j</code> and
|
|
<code>k</code> respectively. We can pair
|
|
<code>nums[j]</code> with all elements up to an including
|
|
<code>nums[k]</code> (besides <code>nums[j]</code>). There are
|
|
exactly \(k-j\) of these. If the indexing confuses you, draw it
|
|
out and prove it to yourself.
|
|
</li>
|
|
<li>
|
|
How do we get our final answer? Accumulate all
|
|
<code>k-j</code> for all <code>i</code>.
|
|
</li>
|
|
</ul>
|
|
<h3>carrying out the plan</h3>
|
|
<p>
|
|
The following approach implements our logic quite elegantly and
|
|
directly. The third and fourth arguments to the
|
|
<code>bisect</code> calls specify <code>lo</code> (inclusive) and
|
|
<code>hi</code> (exclusive) bounds for our search space, mirroring
|
|
the criteria that we search across all indices \(\lt i\).
|
|
</p>
|
|
<div class="code" data-file="cfps-naive.py"></div>
|
|
<h3>optimizing the approach</h3>
|
|
<p>
|
|
If we interpret the criteria this way, the above approach is
|
|
relatively efficient. To improve this approach, we'll need to
|
|
reinterpret the constraints. Forget about the indexing and
|
|
consider the constraint in aggregate. We want to find all \(i,j\)
|
|
with \(x=nums[i]+nums[j]\) such that \(i\neq j,lower\leq x\leq
|
|
upper\).
|
|
</p>
|
|
<p>
|
|
We <i>still</i> need to reduce the “dimensionality” of
|
|
the problem—there are just too many moving parts to consider
|
|
at once. This seems challening. Let's simplify the problem to
|
|
identify helpful ideas: pretend <code>lower</code> does not exist
|
|
(and, of course, that <code>nums</code> is sorted).
|
|
</p>
|
|
<p>
|
|
We're looking for all index pairs with sum \(\leq upper\).
|
|
And behold: (almost) two sum in the wild. This can be accomplished
|
|
with a two-pointers approach—this post is getting quite long
|
|
so we'll skip over why this is the case—but the main
|
|
win here is that we can solve this simplified version of our
|
|
problem in \(O(n)\).
|
|
</p>
|
|
<p>
|
|
Are we any closer to actually solving the problem? Now, we have
|
|
the count of index pairs \(\leq upper\). Is this our answer?
|
|
No—some may be too small, namely, with sum \(\lt lower\).
|
|
Let's exclude those by running our two-pointer approach with
|
|
and upper bound of \(lower-1\) (we want to include \(lower\)).
|
|
Now, our count reflects the total number of index pairs with a sum
|
|
in our interval bound.
|
|
</p>
|
|
<p>
|
|
Note that this really is just running a prefix sum/using the
|
|
“inclusion-exclusion” principle/however you want to
|
|
phrase it.
|
|
</p>
|
|
<div class="code" data-file="cfps-twoptr.py"></div>
|
|
<h3>some more considerations</h3>
|
|
<p>
|
|
The second approach is <i>asymptotically</i> equivalent. However,
|
|
it's still worth considering for two reasons:
|
|
</p>
|
|
<ol>
|
|
<li>
|
|
If an interviewer says “assume <code>nums</code> is
|
|
sorted” or “how can we do
|
|
better?”—you're cooked.
|
|
</li>
|
|
<li>
|
|
(Much) more importantly, it's extremely valuable to be able
|
|
to <i>reconceptualize</i> a problem and look at it from
|
|
different angles. Not being locked in on a solution shows
|
|
perseverance, curiosity, and strong problem-solving abilities.
|
|
</li>
|
|
</ol>
|
|
<h3>asymptotic complexity</h3>
|
|
<p>
|
|
<u>Time Complexity</u>: \(O(nlg(n))\) for both—\(O(n)\) if
|
|
<code>nums</code> is sorted with respect to the second approach.
|
|
</p>
|
|
<p><u>Space Complexity</u>: \(\Theta(1)\) for both.</p>
|
|
</div>
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/most-beautiful-item-for-each-query/description/"
|
|
>most beautiful item for each query</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-09-12">09/12/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>problem statement</h3>
|
|
<p>
|
|
Given an array <code>items</code> of \((price, beauty)\) tuples,
|
|
answer each integer query of \(queries\). The answer to some
|
|
<code>query[i]</code> is the maximum beauty of an item with
|
|
\(price\leq\)<code>items[i][0]</code>.
|
|
</p>
|
|
<h3>understanding the problem</h3>
|
|
<p>
|
|
Focus on one aspect of the problem at a time. To answer a query,
|
|
we need to have considered:
|
|
</p>
|
|
<ol>
|
|
<li>Items with a non-greater price</li>
|
|
<li>The beauty of all such items</li>
|
|
</ol>
|
|
<p>
|
|
Given some query, how can we <i>efficiently</i> identify the
|
|
“last” item with an acceptable price? Leverage the
|
|
most common pre-processing algorithm: sorting. Subsequently, we
|
|
can binary search <code>items</code> (keyed by price, of course)
|
|
to identify all considerable items in \(O(lg(n))\).
|
|
</p>
|
|
<p>
|
|
Great. Now we need to find the item with the largest beauty.
|
|
Naïvely considering all the element is a
|
|
<i>correct</i> approach—but is it correct? Considering our
|
|
binary search \(O(lg(n))\) and beauty search \(O(n)\) across
|
|
\(\Theta(n)\) queries with
|
|
<code>len(items)<=len(queries)</code>\(\leq10^5\), an
|
|
\(O(n^2lg(n))\) approach is certainly unacceptable.
|
|
</p>
|
|
<p>
|
|
Consider alternative approaches to responding to our queries. It
|
|
is clear that answering them in-order yields no benefit (i.e. we
|
|
have to consider each item all over again, per query)—could
|
|
we answer them in another order to save computations?
|
|
</p>
|
|
<p>
|
|
Visualizing our items from left-to-right, we's interested in
|
|
both increasing beauty and prices. If we can scan our items left
|
|
to right, we can certainly “accumulate” a running
|
|
maximal beauty. We can leverage sorting once again to answer our
|
|
queries left-to-right, then re-order them appropriately before
|
|
returning a final answer. Sorting both <code>queries</code> and
|
|
<code>items</code> with a linear scan will take \(O(nlg(n))\)
|
|
time, meeting the constraints.
|
|
</p>
|
|
<h3>carrying out the plan</h3>
|
|
<p>
|
|
A few specifics need to be understood before coding up the
|
|
approach:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
Re-ordering the queries: couple <code>query[i]</code> with
|
|
<code>i</code>, then sort. When responding to queries in sorted
|
|
order, we know where to place them in an output
|
|
container—index <code>i</code>.
|
|
</li>
|
|
<li>
|
|
The linear scan: accumulate a running maximal beauty, starting
|
|
at index <code>0</code>. For some query <code>query</code>, we
|
|
want to consider all items with price less than or equal to
|
|
<code>query</code>. Therefore, loop until this condition is
|
|
<i>violated</i>— the previous index will represent the
|
|
last considered item.
|
|
</li>
|
|
<li>
|
|
Edge cases: it's perfectly possible the last considered
|
|
item is invalid (consider a query cheaper than the cheapest
|
|
item). Return <code>0</code> as specified by the problem
|
|
constraints.
|
|
</li>
|
|
</ul>
|
|
<div class="code" data-file="beauty.cpp"></div>
|
|
<h3>asymptotic complexity</h3>
|
|
<p>
|
|
Let <code>n=len(items)</code> and <code>m=len(queries)</code>.
|
|
There may be more items than queries, or vice versa. Note that a
|
|
“looser” upper bound can be found by analyzing the
|
|
runtime in terms of \(max\{n,m\}\).
|
|
</p>
|
|
<p>
|
|
<u>Time Complexity</u>: \(O(nlg(n)+mlg(m)+m)\in
|
|
O(nlg(n)+mlg(m))\). An argument can be made that because
|
|
<code>queries[i],items[i][{0,1}]</code>\(\leq10^9\), radix sort
|
|
can be leveraged to achieve a time complexity of \(O(d \cdot (n +
|
|
k + m + k))\in O(9\cdot (n + m))\in O(n+m)\).
|
|
</p>
|
|
<p>
|
|
<u>Space Complexity</u>: \(\Theta(1)\), considering that \(O(m)\)
|
|
space must be allocated. If <code>queries</code>/<code
|
|
>items</code
|
|
>
|
|
cannot be modified in-place, increase the space complexity by
|
|
\(m\)/\(n\) respectively.
|
|
</p>
|
|
</div>
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/shortest-subarray-with-or-at-least-k-ii/description/"
|
|
>shortest subarray with or at least k ii</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-09-11">09/11/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>problem statement</h3>
|
|
<p>
|
|
Given an array of non-negative integers \(num\) and some \(k\),
|
|
find the length of the shortest non-empty subarray of nums such
|
|
that its element-wise bitwise OR is greater than or equal to
|
|
\(k\)—return -1 if no such array exists.
|
|
</p>
|
|
<h3>developing an approach</h3>
|
|
<p>Another convoluted, uninspired bitwise-oriented daily.</p>
|
|
<p>
|
|
Anways, we're looking for a subarray that satisfies a
|
|
condition. Considering all subarrays with
|
|
<code>len(nums)</code>\(\leq2\times10^5\) is impractical according
|
|
to the common rule of \(\approx10^8\) computations per second on
|
|
modern CPUs.
|
|
</p>
|
|
<p>
|
|
Say we's building some array <code>xs</code>. Adding another
|
|
element <code>x</code> to this sequence can only increase or
|
|
element-wise bitwise OR. Of course, it makes sense to do this.
|
|
However, consider <code>xs</code> after—it is certainly
|
|
possible that including <code>x</code> finally got us to at least
|
|
<code>k</code>. However, not all of the elements in the array are
|
|
useful now; we should remove some.
|
|
</p>
|
|
<p>
|
|
Which do we remove? Certainly not any from the
|
|
middle—we'd no longer be considering a subarray. We can
|
|
only remove from the beginning.
|
|
</p>
|
|
<p>
|
|
Now, how many times do we remove? While the element-wise bitwise
|
|
OR of <code>xs</code> is \(\geq k\), we can naïvely remove
|
|
from the start of <code>xs</code> to find the smallest subarray.
|
|
</p>
|
|
<p>
|
|
Lastly, what' the state of <code>xs</code> after these
|
|
removals? Now, we (may) have an answer and the element-wise
|
|
bitwise OR of <code>xs</code> is guaranteed to be \(\lt k\).
|
|
Inductively, expand the array to search for a better answer.
|
|
</p>
|
|
<p>
|
|
This approach is generally called a variable-sized “sliding
|
|
window”. Every element of
|
|
<code>nums</code> is only added (considered in the element-wise
|
|
bitwise OR) or removed (discard) one time, yielding an
|
|
asymptotically linear time complexity. In other words, this is a
|
|
realistic approach for our constraints.
|
|
</p>
|
|
<h3>carrying out the plan</h3>
|
|
<p>Plugging in our algorithm to my sliding window framework:</p>
|
|
<div class="code" data-file="msl-naive.py"></div>
|
|
<p>Done, right? No. TLE.</p>
|
|
<p>
|
|
If you thought this solution would work, you move too fast.
|
|
Consider <i>every</i> aspect of an algorithm before implementing
|
|
it. In this case, we (I) overlooked one core question:
|
|
</p>
|
|
<ol style="list-style: none">
|
|
<li><i>How do we maintain our element-wise bitwise OR</i>?</li>
|
|
</ol>
|
|
<p>
|
|
Calculating it by directly maintaining a window of length \(n\)
|
|
takes \(n\) time—with a maximum window size of \(n\), this
|
|
solution is \(O(n^2)\).
|
|
</p>
|
|
<p>
|
|
Let's try again. Adding an element is simple—OR it to
|
|
some cumulative value. Removing an element, not so much.
|
|
Considering some \(x\) to remove, we only unset one of its bits
|
|
from our aggregated OR if it's the “last” one of
|
|
these bits set across all numbers contributing to our aggregated
|
|
value.
|
|
</p>
|
|
<p>
|
|
Thus, to maintain our aggregate OR, we want to map bit
|
|
“indices” to counts. A hashmap (dictionary) or static
|
|
array will do just find. Adding/removing some \(x\) will
|
|
increment/decrement each the counter's bit count at its
|
|
respective position. I like to be uselessly specific
|
|
sometimes—choosing the latter approach, how big should our
|
|
array be? As many bits as represented by the largest of
|
|
\(nums\)—(or \(k\) itself): \[\lfloor \lg({max\{nums,k
|
|
\})}\rfloor+1\]
|
|
</p>
|
|
<p>Note that:</p>
|
|
<ol>
|
|
<li>
|
|
Below we use the
|
|
<a
|
|
target="_blank"
|
|
href="https://artofproblemsolving.com/wiki/index.php/Change_of_base_formula"
|
|
>change of base formula for logarithms</a
|
|
>
|
|
because \(log_2(x)\) is not available in python.
|
|
</li>
|
|
<li>
|
|
It's certainly possible that \(max\{nums, k\}=0\). To avoid
|
|
the invalid calculation \(log(0)\), take the larger of \(1\) and
|
|
this calculation. The number of digits will then (correctly) be
|
|
\(1\) in this special case.
|
|
</li>
|
|
</ol>
|
|
<div class="code" data-file="msl-bitwise.py"></div>
|
|
<h3>asymptotic complexity</h3>
|
|
<p>
|
|
Note that the size of the frequency map is bounded by
|
|
\(lg_{2}({10^9})\approx30\).
|
|
</p>
|
|
<p>
|
|
<u>Space Complexity</u>: Thus, the window uses \(O(1)\) space.
|
|
</p>
|
|
<p>
|
|
<u>Time Complexity</u>: \(\Theta(\)<code>len(nums)</code>\()\)
|
|
—every element of <code>nums</code> is considered at least
|
|
once and takes \(O(1)\) work each to find the element-wise bitwise
|
|
OR.
|
|
</p>
|
|
</div>
|
|
<h2>
|
|
<a
|
|
target="blank"
|
|
href="https://leetcode.com/problems/minimum-array-end/"
|
|
>minimum array end</a
|
|
>
|
|
<span class="post-meta">
|
|
<time datetime="2024-09-10">09/10/2024</time>
|
|
</span>
|
|
</h2>
|
|
<div class="problem-content">
|
|
<h3>problem statement</h3>
|
|
<p>
|
|
Given some \(x\) and \(n\), construct a strictly increasing array
|
|
(say
|
|
<code>nums</code>
|
|
) of length \(n\) such that
|
|
<code>nums[0] & nums[1] ... & nums[n - 1] == x</code>
|
|
, where
|
|
<code>&</code>
|
|
denotes the bitwise AND operator.
|
|
</p>
|
|
<p>
|
|
Finally, return the minimum possible value of
|
|
<code>nums[n - 1]</code>.
|
|
</p>
|
|
<h3>understanding the problem</h3>
|
|
<p>
|
|
The main difficulty in this problem lies in understanding what is
|
|
being asked (intentionally or not, the phrasing is terrible). Some
|
|
initial notes:
|
|
</p>
|
|
<ul>
|
|
<li>The final array need not be constructed</li>
|
|
<li>
|
|
If the element-wise bitwise AND of an array equals
|
|
<code>x</code> if and only if each element has
|
|
<code>x</code>'s bits set—and no other bit it set by
|
|
all elements
|
|
</li>
|
|
<li>
|
|
It makes sense to set <code>nums[0] == x</code> to ensure
|
|
<code>nums[n - 1]</code> is minimal
|
|
</li>
|
|
</ul>
|
|
<h3>developing an approach</h3>
|
|
<p>
|
|
An inductive approach is helpful. Consider the natural question:
|
|
“If I had correctly generated <code>nums[:i]</code>”,
|
|
how could I find <code>nums[i]</code>? In other words,
|
|
<i
|
|
>how can I find the next smallest number such that
|
|
<code>nums</code>
|
|
's element-wise bitwise AND is still \(x\)?</i
|
|
>
|
|
</p>
|
|
<p>
|
|
Hmm... this is tricky. Let's think of a similar problem to
|
|
glean some insight: “Given some \(x\), how can I find the
|
|
next smallest number?”. The answer is, of course, add one
|
|
(bear with me here).
|
|
</p>
|
|
<p>
|
|
We also know that all of <code>nums[i]</code> must have at least
|
|
\(x\)'s bits set. Therefore, we need to alter the unset bits
|
|
of <code>nums[i]</code>.
|
|
</p>
|
|
<p>
|
|
The key insight of this problem is combining these two ideas to
|
|
answer our question:
|
|
<i
|
|
>Just “add one” to <code>nums[i - 1]</code>'s
|
|
unset bits</i
|
|
>. Repeat this to find <code>nums[n - 1]</code>.
|
|
</p>
|
|
<p>
|
|
One last piece is missing—how do we know the element-wise
|
|
bitwise AND is <i>exactly</i> \(x\)? Because
|
|
<code>nums[i > 0]</code> only sets \(x\)'s unset bits, every
|
|
number in <code>nums</code> will have at least \(x\)'s bits
|
|
set. Further, no other bits will be set because \(x\) has them
|
|
unset.
|
|
</p>
|
|
<h3>carrying out the plan</h3>
|
|
<p>Let's flesh out the remaining parts of the algorithm:</p>
|
|
<ul>
|
|
<li>
|
|
<code>len(nums) == n</code> and we initialize
|
|
<code>nums[0] == x</code>. So, we need to “add one”
|
|
<code>n - 1</code> times
|
|
</li>
|
|
<li>
|
|
How do we carry out the additions? We could iterate \(n - 1\)
|
|
times and simulate them. However, we already know how we want to
|
|
alter the unset bits of <code>nums[0]</code> inductively—
|
|
(add one) <i>and</i> how many times we want to do this (\(n -
|
|
1\)). Because we're adding one \(n-1\) times to
|
|
\(x\)'s unset bits (right to left, of course), we simply
|
|
set its unset bits to those of \(n - 1\).
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
The implementation is relatively straightfoward. Traverse \(x\)
|
|
from least-to-most significant bit, setting its \(i\)th unset bit
|
|
to \(n - 1\)'s \(i\)th bit. Use a bitwise mask
|
|
<code>mask</code> to traverse \(x\).
|
|
</p>
|
|
<div class="code" data-file="minend.cpp"></div>
|
|
<h3>asymptotic complexity</h3>
|
|
<p>
|
|
<u>Space Complexity</u>: \(\Theta(1)\)—a constant amount of
|
|
numeric variables are allocated regardless of \(n\) and \(x\).
|
|
</p>
|
|
<p>
|
|
<u>Time Complexity</u>: in the worst case, may need to traverse
|
|
the entirety of \(x\) to distribute every bit of \(n - 1\) to
|
|
\(x\). This occurs if and only if \(x\) is all ones (\(\exists
|
|
k\gt 0 : 2^k-1=x\))). \(x\) and \(n\) have \(lg(x)\) and \(lg(n)\)
|
|
bits respectively, so the solution is \(O(lg(x) + lg(n))\in
|
|
O(log(xn))\). \(1\leq x,n\leq 1e8\), so this runtime is bounded by
|
|
\(O(log(1e8^2))\in O(1)\).
|
|
</p>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</main>
|
|
<site-footer></site-footer>
|
|
<script src="/scripts/common.js"></script>
|
|
<script src="/scripts/post.js"></script>
|
|
</body>
|
|
</html>
|