<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ritesh Gupta</title>
    <description>The latest articles on DEV Community by Ritesh Gupta (@riteshgupta_09).</description>
    <link>https://dev.to/riteshgupta_09</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4126341%2Fab0a62fa-1018-4b65-ac1e-eb369f3b1786.JPG</url>
      <title>DEV Community: Ritesh Gupta</title>
      <link>https://dev.to/riteshgupta_09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/riteshgupta_09"/>
    <language>en</language>
    <item>
      <title>Caching Is Easy. Cache Invalidation Is the Hard Part.</title>
      <dc:creator>Ritesh Gupta</dc:creator>
      <pubDate>Fri, 16 Oct 2026 12:32:03 +0000</pubDate>
      <link>https://dev.to/riteshgupta_09/caching-is-easy-cache-invalidation-is-the-hard-part-o3</link>
      <guid>https://dev.to/riteshgupta_09/caching-is-easy-cache-invalidation-is-the-hard-part-o3</guid>
      <description>&lt;p&gt;Imagine you're building an e-commerce application.&lt;/p&gt;

&lt;p&gt;A user opens a product page. Instead of querying the database every time, you store the product details in Redis. The page loads faster, and your database has less work to do.&lt;/p&gt;

&lt;p&gt;Everything looks great. Then someone updates the product price from ₹999 to ₹1,199. The database has the correct price. But your application keeps showing ₹999.&lt;/p&gt;

&lt;p&gt;Nothing is broken in the database. Your API is responding. Redis is working exactly as expected.&lt;/p&gt;

&lt;p&gt;Yet the user is seeing the wrong information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is the tricky part of caching. Making data faster to access is relatively straightforward. Keeping that cached data accurate is where things get interesting.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's understand why cache invalidation is such an important problem in system design.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Do We Need Caching in the First Place?
&lt;/h2&gt;

&lt;p&gt;Consider a simple application where every request goes directly to the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
     |
     v
 Application Server
     |
     v
   Database
     |
     v
    Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works perfectly well for small applications. But as traffic increases, the database may receive thousands of repeated queries for the same information.&lt;/p&gt;

&lt;p&gt;For example, imagine a popular product page receives 10,000 requests in a short period. If every request queries the database for the same product details, we're doing a lot of repetitive work.&lt;/p&gt;

&lt;p&gt;Instead, we can store frequently accessed data in a cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
     |
     v
 Application Server
     |
     v
    Cache
     |
     |-- Cache HIT --&amp;gt; Return cached data
     |
     |-- Cache MISS --&amp;gt; Query database
                           |
                           v
                      Store in cache
                           |
                           v
                       Return data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A cache is a fast storage layer that keeps copies of data so the application can retrieve them without repeatedly accessing the original data source.&lt;/p&gt;

&lt;p&gt;Redis is a popular choice, although caches can also exist inside an application, in a browser, or at a CDN edge.&lt;/p&gt;

&lt;p&gt;The benefits are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower response latency&lt;/li&gt;
&lt;li&gt;Fewer database queries&lt;/li&gt;
&lt;li&gt;Reduced load on backend services&lt;/li&gt;
&lt;li&gt;Better performance during periods of high traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there's one important detail: &lt;strong&gt;a cache stores a copy of the data, not the original source of truth.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That distinction explains the problem we're about to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What Exactly Is Cache Invalidation?
&lt;/h2&gt;

&lt;p&gt;Cache invalidation means making cached data unusable when it is no longer valid, so that the application can fetch or generate a correct replacement.&lt;/p&gt;

&lt;p&gt;Let's continue with our e-commerce example.&lt;/p&gt;

&lt;p&gt;Initially, the database contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application fetches this record and caches it.&lt;/p&gt;

&lt;p&gt;A few minutes later, an administrator updates the price:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1199&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database now contains ₹1,199, but the cache still contains ₹999.&lt;/p&gt;

&lt;p&gt;If the application returns the cached record, the customer sees an outdated price.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;stale data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The challenge is deciding when cached data should be removed, refreshed, or treated as invalid.&lt;/p&gt;

&lt;p&gt;And the difficulty increases when multiple application servers, caches, and services are involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Three Common Approaches to Cache Invalidation
&lt;/h2&gt;

&lt;p&gt;There isn't one universal solution. The right approach depends on how frequently the data changes and how much staleness the application can tolerate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 1: TTL-Based Expiration
&lt;/h3&gt;

&lt;p&gt;TTL stands for &lt;em&gt;Time to Live&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It defines how long an entry can remain in the cache before it expires.&lt;/p&gt;

&lt;p&gt;For example, we might cache product details for five minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product:101&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;product_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;ex=300&lt;/code&gt; represents a 300-second expiration when using the Redis Python client.&lt;/p&gt;

&lt;p&gt;After the TTL expires, Redis treats the entry as expired. The next cache lookup will need to retrieve the data again if no valid entry exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple to implement&lt;/li&gt;
&lt;li&gt;Automatically limits how long old entries remain cached&lt;/li&gt;
&lt;li&gt;Useful for data that doesn't require immediate updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data may remain stale until the TTL expires&lt;/li&gt;
&lt;li&gt;Frequently accessed entries may still need to be recomputed after expiration&lt;/li&gt;
&lt;li&gt;Short TTLs increase cache misses and database load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important point: TTL does not guarantee that data stays fresh for the entire time window. It only limits how long an entry remains valid according to its expiration.&lt;/p&gt;

&lt;p&gt;For example, if a product price changes one second after the cache is populated, users could still see the old price for almost five minutes.&lt;/p&gt;

&lt;p&gt;TTL is useful when a little staleness is acceptable. It isn't sufficient by itself when updates must become visible quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2: Cache-Aside Pattern
&lt;/h3&gt;

&lt;p&gt;Cache-aside is one of the most common caching patterns in backend applications.&lt;/p&gt;

&lt;p&gt;The application checks the cache first. If the data isn't there, it reads from the database and stores the result in the cache.&lt;/p&gt;

&lt;p&gt;Here's a simplified Python example using a Redis client and a database access function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check Redis for the product.&lt;/li&gt;
&lt;li&gt;If the entry exists, return it.&lt;/li&gt;
&lt;li&gt;Otherwise, query the database.&lt;/li&gt;
&lt;li&gt;Store the result in Redis with a TTL.&lt;/li&gt;
&lt;li&gt;Return the result to the caller.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach keeps the application in control of when data is loaded into the cache.&lt;/p&gt;

&lt;p&gt;But notice something important: &lt;strong&gt;cache-aside describes how data is read and populated. It doesn't automatically solve invalidation after an update.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to handle writes separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 3: Explicit Invalidation After a Write
&lt;/h3&gt;

&lt;p&gt;Suppose an administrator updates a product price.&lt;/p&gt;

&lt;p&gt;A common strategy is to update the database first and then delete the corresponding cache entry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_product_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;new_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;redis&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next request won't find the old cache entry. It can read the updated product from the database and populate the cache again.&lt;/p&gt;

&lt;p&gt;This is a simple and effective strategy for many applications.&lt;/p&gt;

&lt;p&gt;However, there's a subtle issue.&lt;/p&gt;

&lt;p&gt;What happens if the database update succeeds but the cache deletion fails?&lt;/p&gt;

&lt;p&gt;The application could continue serving stale data until the cache entry expires or another mechanism removes it.&lt;/p&gt;

&lt;p&gt;Distributed systems also introduce race conditions. For example, a request that started reading the old database value before the update might write that old value into the cache after the invalidation occurs.&lt;/p&gt;

&lt;p&gt;So even explicit deletion isn't a complete guarantee of consistency under every possible failure or concurrency scenario.&lt;/p&gt;

&lt;p&gt;For systems where stale data is especially costly, engineers may need retries, reliable event processing, versioning, or other coordination mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Cache Invalidation vs. Cache Refresh
&lt;/h2&gt;

&lt;p&gt;These terms are related, but they aren't identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invalidation&lt;/strong&gt; makes an existing cache entry unusable. The next request may fetch fresh data from the source of truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refresh&lt;/strong&gt; updates the cached value with newer data, either when a request arrives or in the background.&lt;/p&gt;

&lt;p&gt;For example, after a product price changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Invalidation: Delete &lt;code&gt;product:101&lt;/code&gt; from Redis.&lt;/li&gt;
&lt;li&gt;Refresh: Fetch the updated product and overwrite &lt;code&gt;product:101&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Invalidation is often simpler because the application doesn't have to immediately rebuild every cached value.&lt;/p&gt;

&lt;p&gt;Refreshing can be useful when an entry is expensive to regenerate and likely to be requested again soon.&lt;/p&gt;

&lt;p&gt;The trade-off is that refresh logic introduces additional work and failure cases. A refresh can fail, or it can overwrite newer data with an older result if concurrency isn't handled carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What Happens When Multiple Servers Are Involved?
&lt;/h2&gt;

&lt;p&gt;So far, we've considered one application and one cache.&lt;/p&gt;

&lt;p&gt;Now imagine your application has ten server instances, all reading and writing product data.&lt;/p&gt;

&lt;p&gt;If each server maintains its own in-memory cache, invalidating data on one server won't automatically invalidate it on the others.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Load Balancer
                       |
          +------------+------------+
          |            |            |
          v            v            v
       Server A     Server B     Server C
          |            |            |
       Cache A      Cache B      Cache C
          |            |            |
          +------------+------------+
                       |
                    Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one reason shared caching systems such as Redis are useful: multiple application instances can access the same cache.&lt;/p&gt;

&lt;p&gt;But a shared cache doesn't eliminate every consistency problem.&lt;/p&gt;

&lt;p&gt;There can still be concurrent requests, delayed invalidation, failed operations, replica lag, and stale values already held by other layers, such as application memory or a CDN.&lt;/p&gt;

&lt;p&gt;For larger systems, engineers may use mechanisms such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event-driven invalidation:&lt;/strong&gt; Publish an event when data changes and have relevant services invalidate their caches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioned cache keys:&lt;/strong&gt; Include a version in the key so old entries are no longer selected after an update.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL as a fallback:&lt;/strong&gt; Ensure that entries eventually expire even if an invalidation event is missed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable event delivery:&lt;/strong&gt; Use durable messaging or an outbox pattern when losing invalidation events would be unacceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These approaches have their own trade-offs. Event-driven invalidation, for example, can reduce stale-data windows, but it doesn't automatically provide immediate consistency because events may be delayed or retried.&lt;/p&gt;

&lt;p&gt;The important lesson is that cache invalidation becomes a coordination problem as a system grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A Related Problem: Cache Stampede
&lt;/h2&gt;

&lt;p&gt;There's another issue worth understanding.&lt;/p&gt;

&lt;p&gt;Imagine a popular cached item expires just as thousands of users request it.&lt;/p&gt;

&lt;p&gt;Many requests miss the cache at approximately the same time. They all query the database and try to repopulate the same entry.&lt;/p&gt;

&lt;p&gt;This sudden burst of work is commonly called a &lt;strong&gt;cache stampede&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of reducing database load, the cache expiration creates a spike in database traffic.&lt;/p&gt;

&lt;p&gt;Some ways to mitigate this include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request coalescing:&lt;/strong&gt; Let one request load the missing value while other requests wait for its result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL jitter:&lt;/strong&gt; Add a small random variation to expiration times to avoid many entries expiring simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background refresh:&lt;/strong&gt; Refresh frequently accessed data before it expires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale-while-revalidate:&lt;/strong&gt; Serve an older value temporarily while refreshing it in the background, when the application can safely tolerate that staleness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These techniques solve a different problem from invalidation itself, but they matter when designing a reliable caching strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. How Do You Choose the Right Strategy?
&lt;/h2&gt;

&lt;p&gt;There is no need to use the most complicated solution everywhere.&lt;/p&gt;

&lt;p&gt;Start by asking a few questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How frequently does the data change?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For mostly static content, a longer TTL may be enough. For frequently updated records, explicit invalidation may be more appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much staleness is acceptable?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A slightly outdated recommendation might be acceptable. An outdated account balance or incorrect price at checkout can have much more serious consequences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens if invalidation fails?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If stale data can cause significant harm, think beyond a simple cache deletion. Consider retries, durable events, versioning, and a clear consistency guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How expensive is recomputing the data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If regenerating a value is costly, refreshing it before expiration or coalescing concurrent misses may help.&lt;/p&gt;

&lt;p&gt;The goal isn't to eliminate every possible stale read at any cost. It's to choose a strategy whose performance, complexity, and consistency guarantees fit the requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. The Biggest Lesson I Took From This
&lt;/h2&gt;

&lt;p&gt;Before exploring caching in depth, it's easy to think of it as a simple optimization: put frequently accessed data into Redis and let the application read it faster.&lt;/p&gt;

&lt;p&gt;But caching introduces another copy of the data, and now the system has to manage the relationship between that copy and the source of truth.&lt;/p&gt;

&lt;p&gt;That changes the problem.&lt;/p&gt;

&lt;p&gt;You're no longer thinking only about how quickly a request can return a response. You're also thinking about what happens when data changes, requests overlap, network calls fail, and multiple services disagree temporarily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A fast system isn't necessarily a correct system. And a good system design has to account for both.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Caching is powerful, but it works best when you understand what you're trading away, how stale data is handled, and what guarantees your application actually needs.&lt;/p&gt;

&lt;p&gt;The next time you add a cache to a project, don't stop at asking, "How can I make this faster?"&lt;/p&gt;

&lt;p&gt;Also ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"When this data changes, how will the rest of my system find out?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question can make a much bigger difference than adding another layer of caching.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to Practice System Design Beyond Theory?
&lt;/h2&gt;

&lt;p&gt;Understanding concepts like caching, cache invalidation, and distributed systems is a great start. But the real learning happens when you try to apply them to actual system design problems.&lt;/p&gt;

&lt;p&gt;That's one reason I've been exploring &lt;strong&gt;&lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;ScaleDojo&lt;/a&gt;&lt;/strong&gt; — a platform for learning and practicing system design through interactive challenges.&lt;/p&gt;

&lt;p&gt;Instead of only reading about architectures, you can work through design problems, think about trade-offs, and improve your understanding of how real-world systems are put together.&lt;/p&gt;

&lt;p&gt;If you're learning system design for backend engineering interviews or want to get better at designing scalable applications, it's worth checking out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore ScaleDojo:&lt;/strong&gt; &lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;https://scaledojo.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My takeaway: don't just memorize how distributed systems work. Practice making the decisions that make them work.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>backend</category>
      <category>python</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Celebrity Problem: From Brute Force to O(n)</title>
      <dc:creator>Ritesh Gupta</dc:creator>
      <pubDate>Sun, 11 Oct 2026 05:49:18 +0000</pubDate>
      <link>https://dev.to/riteshgupta_09/the-celebrity-problem-from-brute-force-to-on-1ap9</link>
      <guid>https://dev.to/riteshgupta_09/the-celebrity-problem-from-brute-force-to-on-1ap9</guid>
      <description>&lt;p&gt;Imagine you walk into a party with a few hundred guests. You don't know who anyone is, but you're told that one person there might be a &lt;strong&gt;celebrity&lt;/strong&gt;. You can only ask questions of the form:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, do you know that person over there?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How many questions do you need to ask to find the celebrity, or to prove there isn't one?&lt;/p&gt;

&lt;p&gt;My first instinct when I met this problem was "just ask everyone about everyone." It works, but it's slow. By the end of this post you'll see how to do it with &lt;strong&gt;one pass and no extra memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Grab a coffee. We'll build this up step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  What exactly is a celebrity?
&lt;/h2&gt;

&lt;p&gt;In this problem, a celebrity is someone who satisfies &lt;strong&gt;both&lt;/strong&gt; of these rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Everyone knows them.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;They know nobody.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. Two rules, and both must hold.&lt;/p&gt;

&lt;p&gt;You're given a square matrix &lt;code&gt;M&lt;/code&gt; of size &lt;code&gt;n x n&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M[i][j] = 1&lt;/code&gt; means person &lt;code&gt;i&lt;/code&gt; knows person &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M[i][j] = 0&lt;/code&gt; means person &lt;code&gt;i&lt;/code&gt; does not know person &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your job: return the celebrity's index, or &lt;code&gt;-1&lt;/code&gt; if there isn't one.&lt;/p&gt;

&lt;h3&gt;
  
  
  A tiny example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 0 knows only person 2
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 1 knows only person 2
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 2 knows nobody
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 3 knows persons 1 and 2
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the same thing as a picture. An arrow &lt;code&gt;A -&amp;gt; B&lt;/code&gt; means "A knows B":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    0 -----+
           |
           v
    1 ---&amp;gt; 2 &amp;lt;--- 3
           ^       |
           |       |
           +-------+
     (3 also knows 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everyone points at &lt;strong&gt;person 2&lt;/strong&gt;, and person 2 points at nobody. So the answer is &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Quick sanity check:&lt;/strong&gt; can there ever be two celebrities? Think about it for a second before reading on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
No. If A and B were both celebrities, then A would have to know B (because everyone knows a celebrity). But a celebrity knows nobody. That's a contradiction, so there is &lt;strong&gt;at most one&lt;/strong&gt; celebrity. This fact is the secret ingredient of the fast solution later.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 1: Brute force
&lt;/h2&gt;

&lt;p&gt;The most natural idea is to test every person one by one.&lt;/p&gt;

&lt;p&gt;For each person &lt;code&gt;c&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check that &lt;code&gt;c&lt;/code&gt; knows nobody (their entire row is 0, apart from themselves).&lt;/li&gt;
&lt;li&gt;Check that everyone knows &lt;code&gt;c&lt;/code&gt; (their entire column is 1, apart from themselves).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity_brute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;is_celebrity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="c1"&gt;# c must not know i, and i must know c
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;is_celebrity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_celebrity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How slow is it?
&lt;/h3&gt;

&lt;p&gt;We have an outer loop over &lt;code&gt;n&lt;/code&gt; people and an inner loop over &lt;code&gt;n&lt;/code&gt; people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time: O(n²)&lt;/strong&gt;, &lt;strong&gt;Space: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For 1,000 people that's about a million checks. For 100,000 people it's ten billion. That's the point where your laptop fan starts to sound like a jet engine.&lt;/p&gt;

&lt;p&gt;Can we do better? Let's look for wasted work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The key insight: every question kills someone
&lt;/h2&gt;

&lt;p&gt;Here's the idea that changes everything. Pick any two people, &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, and ask just &lt;strong&gt;one&lt;/strong&gt; question: &lt;em&gt;"Does A know B?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are only two possible answers, and &lt;strong&gt;both of them eliminate somebody&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;th&gt;What it tells us&lt;/th&gt;
&lt;th&gt;Who is eliminated?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt;, A knows B&lt;/td&gt;
&lt;td&gt;A knows someone, but a celebrity knows nobody&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt; can't be the celebrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt;, A doesn't know B&lt;/td&gt;
&lt;td&gt;B isn't known by everyone, but a celebrity must be&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;B&lt;/strong&gt; can't be the celebrity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read that table once more. It's the entire trick.&lt;/p&gt;

&lt;p&gt;One question, one person eliminated. Always. No matter what.&lt;/p&gt;

&lt;p&gt;So if we start with &lt;code&gt;n&lt;/code&gt; people, after &lt;code&gt;n - 1&lt;/code&gt; questions we're left with exactly &lt;strong&gt;one candidate&lt;/strong&gt;. Not the celebrity yet, just the only person who hasn't been ruled out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 2: Eliminate with a stack
&lt;/h2&gt;

&lt;p&gt;Let's turn that insight into an algorithm. A stack is a nice way to picture it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push everyone onto the stack.&lt;/li&gt;
&lt;li&gt;Pop two people, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; knows &lt;code&gt;b&lt;/code&gt;, then &lt;code&gt;a&lt;/code&gt; is out, so push &lt;code&gt;b&lt;/code&gt; back. Otherwise &lt;code&gt;b&lt;/code&gt; is out, so push &lt;code&gt;a&lt;/code&gt; back.&lt;/li&gt;
&lt;li&gt;Repeat until one person is left.&lt;/li&gt;
&lt;li&gt;Verify that person (more on this soon).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity_stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="c1"&gt;# a knows b, so a is not a celebrity
&lt;/span&gt;            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                 &lt;span class="c1"&gt;# a doesn't know b, so b is not a celebrity
&lt;/span&gt;            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Verification step
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time: O(n)&lt;/strong&gt;, &lt;strong&gt;Space: O(n)&lt;/strong&gt; for the stack.&lt;/p&gt;

&lt;p&gt;We got linear time. But storing everyone in a stack feels like overkill. Can we get rid of it?&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 3: Two pointers, no extra memory
&lt;/h2&gt;

&lt;p&gt;Why keep a stack when we only ever hold one survivor at a time? We can just remember a single variable called &lt;code&gt;candidate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by assuming person &lt;code&gt;0&lt;/code&gt; is the celebrity.&lt;/li&gt;
&lt;li&gt;Walk through everyone else, one at a time.&lt;/li&gt;
&lt;li&gt;If the current candidate &lt;strong&gt;knows&lt;/strong&gt; person &lt;code&gt;i&lt;/code&gt;, the candidate is out and &lt;code&gt;i&lt;/code&gt; becomes the new candidate.&lt;/li&gt;
&lt;li&gt;Otherwise &lt;code&gt;i&lt;/code&gt; is out, and we keep our candidate.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 1: find a possible candidate
&lt;/span&gt;    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 2: verify the candidate
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole solution. Two small loops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time: O(n)&lt;/strong&gt;, &lt;strong&gt;Space: O(1)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's trace it by hand
&lt;/h2&gt;

&lt;p&gt;Using our earlier matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 1: find the candidate
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;candidate&lt;/th&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;&lt;code&gt;M[candidate][i]&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;start&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Assume 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 doesn't know 1, so &lt;strong&gt;1 is out&lt;/strong&gt;. Keep 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0 knows 2, so &lt;strong&gt;0 is out&lt;/strong&gt;. Candidate becomes 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2 doesn't know 3, so &lt;strong&gt;3 is out&lt;/strong&gt;. Keep 2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Candidate after phase 1: &lt;strong&gt;2&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: verify
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Person&lt;/th&gt;
&lt;th&gt;Does 2 know them? (must be 0)&lt;/th&gt;
&lt;th&gt;Do they know 2? (must be 1)&lt;/th&gt;
&lt;th&gt;OK?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][0] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[0][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][1] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[1][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][3] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[3][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All checks pass, so the celebrity is &lt;strong&gt;person 2&lt;/strong&gt;. 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Wait, why do we need Phase 2?
&lt;/h2&gt;

&lt;p&gt;This is the part most beginners (including me, the first time) skip.&lt;/p&gt;

&lt;p&gt;Phase 1 only tells us: &lt;em&gt;"everyone else has been ruled out."&lt;/em&gt; It does &lt;strong&gt;not&lt;/strong&gt; tell us the survivor is actually a celebrity. Maybe there is no celebrity at all!&lt;/p&gt;

&lt;p&gt;Try this matrix where nobody knows anybody:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Phase 1 hands us person &lt;code&gt;0&lt;/code&gt; as the candidate (nobody ever knew anyone, so the candidate never changed). But person 0 is &lt;strong&gt;not&lt;/strong&gt; a celebrity, because nobody knows them. Phase 2 catches this and correctly returns &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; elimination finds the only &lt;em&gt;possible&lt;/em&gt; answer. Verification confirms it's a &lt;em&gt;real&lt;/em&gt; answer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Comparing all approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Space&lt;/th&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brute force&lt;/td&gt;
&lt;td&gt;O(n²)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;Test every person fully&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack elimination&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;Eliminate one person per question&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two pointer candidate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same idea, no stack needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And here's how the number of questions grows as &lt;code&gt;n&lt;/code&gt; grows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;n (people)&lt;/th&gt;
&lt;th&gt;Brute force (about n²)&lt;/th&gt;
&lt;th&gt;Optimized (about 3n)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;1,000,000&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100,000&lt;/td&gt;
&lt;td&gt;10,000,000,000&lt;/td&gt;
&lt;td&gt;300,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The optimized version needs about &lt;code&gt;n - 1&lt;/code&gt; questions to find a candidate, plus about &lt;code&gt;2(n - 1)&lt;/code&gt; to verify. That is roughly &lt;code&gt;3n&lt;/code&gt;, which is still O(n).&lt;/p&gt;




&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the verification phase.&lt;/strong&gt; The most common bug. See the all zeros matrix above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking &lt;code&gt;M[i][i]&lt;/code&gt;.&lt;/strong&gt; A person knowing themselves is usually &lt;code&gt;0&lt;/code&gt; or ignored. Always skip &lt;code&gt;i == candidate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixing up the direction.&lt;/strong&gt; &lt;code&gt;M[a][b]&lt;/code&gt; means "a knows b", not the other way around. Read it out loud while coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using the wrong elimination rule.&lt;/strong&gt; If &lt;code&gt;a&lt;/code&gt; knows &lt;code&gt;b&lt;/code&gt;, eliminate &lt;code&gt;a&lt;/code&gt; (not &lt;code&gt;b&lt;/code&gt;). I've flipped this more than once at 1 AM.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The interview version
&lt;/h2&gt;

&lt;p&gt;In interviews you often don't get the matrix. You get a function instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is the same, and the number of calls to &lt;code&gt;knows&lt;/code&gt; is what gets measured. The same algorithm drops right in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findCelebrity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small optimization worth mentioning to your interviewer: you can &lt;strong&gt;cache&lt;/strong&gt; results of &lt;code&gt;knows&lt;/code&gt; so you never ask the same question twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick quiz
&lt;/h2&gt;

&lt;p&gt;Test yourself before looking at the answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1.&lt;/strong&gt; In Phase 1, &lt;code&gt;candidate = 4&lt;/code&gt; and &lt;code&gt;M[4][7] = 0&lt;/code&gt;. What happens?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
Person 4 doesn't know person 7, so &lt;strong&gt;7 cannot be the celebrity&lt;/strong&gt; (a celebrity must be known by everyone). We keep 4 as the candidate and move on.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2.&lt;/strong&gt; Can the algorithm return a wrong answer without Phase 2?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
Yes. Phase 1 always produces a candidate, even when no celebrity exists. Phase 2 is what confirms it.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3.&lt;/strong&gt; What would the time complexity be if we verified &lt;em&gt;every&lt;/em&gt; person instead of only the final candidate?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
That's just the brute force approach again, so &lt;strong&gt;O(n²)&lt;/strong&gt;. The whole point of elimination is that we only fully verify one person.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A celebrity is known by everyone and knows no one.&lt;/li&gt;
&lt;li&gt;There can be &lt;strong&gt;at most one&lt;/strong&gt; celebrity.&lt;/li&gt;
&lt;li&gt;Every question &lt;code&gt;knows(a, b)&lt;/code&gt; rules out exactly one of the two people.&lt;/li&gt;
&lt;li&gt;Eliminate first, &lt;strong&gt;verify second&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Brute force is O(n²). The elimination approach is &lt;strong&gt;O(n) time and O(1) space&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bigger lesson isn't about celebrities. It's this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Can each step of my algorithm throw away part of the problem?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That mindset shows up in binary search, two pointers, monotonic stacks, and many other patterns. Once you start looking for it, you'll see it everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  🥋 Want to practice problems like this?
&lt;/h2&gt;

&lt;p&gt;Understanding the solution is one thing.&lt;/p&gt;

&lt;p&gt;Being able to solve a new problem on your own is another.&lt;/p&gt;

&lt;p&gt;That's why I've been exploring &lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;ScaleDojo&lt;/a&gt;, a hands-on platform for practicing system design, LLD, API design, and algorithmic problem-solving.&lt;/p&gt;

&lt;p&gt;Instead of only reading the solution, you can practice concepts through interactive challenges and get feedback on your approach.&lt;/p&gt;

&lt;p&gt;If you're preparing for technical interviews or simply trying to become better at problem-solving, it's worth checking out:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Try ScaleDojo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More practice problems
&lt;/h2&gt;

&lt;p&gt;If you want to keep going with the same pattern, try these next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/find-the-celebrity/" rel="noopener noreferrer"&gt;Find the Celebrity (LeetCode 277)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/find-the-town-judge/" rel="noopener noreferrer"&gt;Find the Town Judge (LeetCode 997)&lt;/a&gt;, a very close cousin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/find-center-of-star-graph/" rel="noopener noreferrer"&gt;Find Center of Star Graph (LeetCode 1791)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Did you solve this with the stack, two pointers, or something even cleverer? Drop your approach (or your favorite language) in the comments. I'd love to see a Rust or Go version!&lt;/p&gt;

&lt;p&gt;And one more question for you: &lt;strong&gt;what's the first thing you'd check if your app slowed down after hitting 10x traffic?&lt;/strong&gt; I'm curious what everyone's instinct is.&lt;/p&gt;

&lt;p&gt;If this post helped you, a ❤️ or 🦄 helps more beginners find it, and following me means you won't miss the next one in this series. Thanks for reading, and happy coding!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>python</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>The Celebrity Problem: From Brute Force to O(n)</title>
      <dc:creator>Ritesh Gupta</dc:creator>
      <pubDate>Sun, 11 Oct 2026 05:46:12 +0000</pubDate>
      <link>https://dev.to/riteshgupta_09/the-celebrity-problem-from-brute-force-to-on-4mjk</link>
      <guid>https://dev.to/riteshgupta_09/the-celebrity-problem-from-brute-force-to-on-4mjk</guid>
      <description>&lt;p&gt;Imagine you walk into a party with a few hundred guests. You don't know who anyone is, but you're told that one person there might be a &lt;strong&gt;celebrity&lt;/strong&gt;. You can only ask questions of the form:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, do you know that person over there?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How many questions do you need to ask to find the celebrity, or to prove there isn't one?&lt;/p&gt;

&lt;p&gt;My first instinct when I met this problem was "just ask everyone about everyone." It works, but it's slow. By the end of this post you'll see how to do it with &lt;strong&gt;one pass and no extra memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Grab a coffee. We'll build this up step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  What exactly is a celebrity?
&lt;/h2&gt;

&lt;p&gt;In this problem, a celebrity is someone who satisfies &lt;strong&gt;both&lt;/strong&gt; of these rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Everyone knows them.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;They know nobody.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. Two rules, and both must hold.&lt;/p&gt;

&lt;p&gt;You're given a square matrix &lt;code&gt;M&lt;/code&gt; of size &lt;code&gt;n x n&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M[i][j] = 1&lt;/code&gt; means person &lt;code&gt;i&lt;/code&gt; knows person &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M[i][j] = 0&lt;/code&gt; means person &lt;code&gt;i&lt;/code&gt; does not know person &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your job: return the celebrity's index, or &lt;code&gt;-1&lt;/code&gt; if there isn't one.&lt;/p&gt;

&lt;h3&gt;
  
  
  A tiny example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 0 knows only person 2
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 1 knows only person 2
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 2 knows nobody
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# person 3 knows persons 1 and 2
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the same thing as a picture. An arrow &lt;code&gt;A -&amp;gt; B&lt;/code&gt; means "A knows B":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    0 -----+
           |
           v
    1 ---&amp;gt; 2 &amp;lt;--- 3
           ^       |
           |       |
           +-------+
     (3 also knows 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everyone points at &lt;strong&gt;person 2&lt;/strong&gt;, and person 2 points at nobody. So the answer is &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Quick sanity check:&lt;/strong&gt; can there ever be two celebrities? Think about it for a second before reading on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
No. If A and B were both celebrities, then A would have to know B (because everyone knows a celebrity). But a celebrity knows nobody. That's a contradiction, so there is &lt;strong&gt;at most one&lt;/strong&gt; celebrity. This fact is the secret ingredient of the fast solution later.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 1: Brute force
&lt;/h2&gt;

&lt;p&gt;The most natural idea is to test every person one by one.&lt;/p&gt;

&lt;p&gt;For each person &lt;code&gt;c&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check that &lt;code&gt;c&lt;/code&gt; knows nobody (their entire row is 0, apart from themselves).&lt;/li&gt;
&lt;li&gt;Check that everyone knows &lt;code&gt;c&lt;/code&gt; (their entire column is 1, apart from themselves).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity_brute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;is_celebrity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="c1"&gt;# c must not know i, and i must know c
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;is_celebrity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_celebrity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How slow is it?
&lt;/h3&gt;

&lt;p&gt;We have an outer loop over &lt;code&gt;n&lt;/code&gt; people and an inner loop over &lt;code&gt;n&lt;/code&gt; people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time: O(n²)&lt;/strong&gt;, &lt;strong&gt;Space: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For 1,000 people that's about a million checks. For 100,000 people it's ten billion. That's the point where your laptop fan starts to sound like a jet engine.&lt;/p&gt;

&lt;p&gt;Can we do better? Let's look for wasted work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The key insight: every question kills someone
&lt;/h2&gt;

&lt;p&gt;Here's the idea that changes everything. Pick any two people, &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, and ask just &lt;strong&gt;one&lt;/strong&gt; question: &lt;em&gt;"Does A know B?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are only two possible answers, and &lt;strong&gt;both of them eliminate somebody&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;th&gt;What it tells us&lt;/th&gt;
&lt;th&gt;Who is eliminated?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt;, A knows B&lt;/td&gt;
&lt;td&gt;A knows someone, but a celebrity knows nobody&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt; can't be the celebrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt;, A doesn't know B&lt;/td&gt;
&lt;td&gt;B isn't known by everyone, but a celebrity must be&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;B&lt;/strong&gt; can't be the celebrity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read that table once more. It's the entire trick.&lt;/p&gt;

&lt;p&gt;One question, one person eliminated. Always. No matter what.&lt;/p&gt;

&lt;p&gt;So if we start with &lt;code&gt;n&lt;/code&gt; people, after &lt;code&gt;n - 1&lt;/code&gt; questions we're left with exactly &lt;strong&gt;one candidate&lt;/strong&gt;. Not the celebrity yet, just the only person who hasn't been ruled out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 2: Eliminate with a stack
&lt;/h2&gt;

&lt;p&gt;Let's turn that insight into an algorithm. A stack is a nice way to picture it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push everyone onto the stack.&lt;/li&gt;
&lt;li&gt;Pop two people, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; knows &lt;code&gt;b&lt;/code&gt;, then &lt;code&gt;a&lt;/code&gt; is out, so push &lt;code&gt;b&lt;/code&gt; back. Otherwise &lt;code&gt;b&lt;/code&gt; is out, so push &lt;code&gt;a&lt;/code&gt; back.&lt;/li&gt;
&lt;li&gt;Repeat until one person is left.&lt;/li&gt;
&lt;li&gt;Verify that person (more on this soon).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity_stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="c1"&gt;# a knows b, so a is not a celebrity
&lt;/span&gt;            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                 &lt;span class="c1"&gt;# a doesn't know b, so b is not a celebrity
&lt;/span&gt;            &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Verification step
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time: O(n)&lt;/strong&gt;, &lt;strong&gt;Space: O(n)&lt;/strong&gt; for the stack.&lt;/p&gt;

&lt;p&gt;We got linear time. But storing everyone in a stack feels like overkill. Can we get rid of it?&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt 3: Two pointers, no extra memory
&lt;/h2&gt;

&lt;p&gt;Why keep a stack when we only ever hold one survivor at a time? We can just remember a single variable called &lt;code&gt;candidate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by assuming person &lt;code&gt;0&lt;/code&gt; is the celebrity.&lt;/li&gt;
&lt;li&gt;Walk through everyone else, one at a time.&lt;/li&gt;
&lt;li&gt;If the current candidate &lt;strong&gt;knows&lt;/strong&gt; person &lt;code&gt;i&lt;/code&gt;, the candidate is out and &lt;code&gt;i&lt;/code&gt; becomes the new candidate.&lt;/li&gt;
&lt;li&gt;Otherwise &lt;code&gt;i&lt;/code&gt; is out, and we keep our candidate.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_celebrity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 1: find a possible candidate
&lt;/span&gt;    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 2: verify the candidate
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole solution. Two small loops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time: O(n)&lt;/strong&gt;, &lt;strong&gt;Space: O(1)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's trace it by hand
&lt;/h2&gt;

&lt;p&gt;Using our earlier matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 1: find the candidate
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;candidate&lt;/th&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;&lt;code&gt;M[candidate][i]&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;start&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Assume 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 doesn't know 1, so &lt;strong&gt;1 is out&lt;/strong&gt;. Keep 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0 knows 2, so &lt;strong&gt;0 is out&lt;/strong&gt;. Candidate becomes 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2 doesn't know 3, so &lt;strong&gt;3 is out&lt;/strong&gt;. Keep 2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Candidate after phase 1: &lt;strong&gt;2&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: verify
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Person&lt;/th&gt;
&lt;th&gt;Does 2 know them? (must be 0)&lt;/th&gt;
&lt;th&gt;Do they know 2? (must be 1)&lt;/th&gt;
&lt;th&gt;OK?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][0] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[0][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][1] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[1][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[2][3] = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M[3][2] = 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All checks pass, so the celebrity is &lt;strong&gt;person 2&lt;/strong&gt;. 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  Wait, why do we need Phase 2?
&lt;/h2&gt;

&lt;p&gt;This is the part most beginners (including me, the first time) skip.&lt;/p&gt;

&lt;p&gt;Phase 1 only tells us: &lt;em&gt;"everyone else has been ruled out."&lt;/em&gt; It does &lt;strong&gt;not&lt;/strong&gt; tell us the survivor is actually a celebrity. Maybe there is no celebrity at all!&lt;/p&gt;

&lt;p&gt;Try this matrix where nobody knows anybody:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Phase 1 hands us person &lt;code&gt;0&lt;/code&gt; as the candidate (nobody ever knew anyone, so the candidate never changed). But person 0 is &lt;strong&gt;not&lt;/strong&gt; a celebrity, because nobody knows them. Phase 2 catches this and correctly returns &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; elimination finds the only &lt;em&gt;possible&lt;/em&gt; answer. Verification confirms it's a &lt;em&gt;real&lt;/em&gt; answer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Comparing all approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Space&lt;/th&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Brute force&lt;/td&gt;
&lt;td&gt;O(n²)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;Test every person fully&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack elimination&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;Eliminate one person per question&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two pointer candidate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Same idea, no stack needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And here's how the number of questions grows as &lt;code&gt;n&lt;/code&gt; grows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;n (people)&lt;/th&gt;
&lt;th&gt;Brute force (about n²)&lt;/th&gt;
&lt;th&gt;Optimized (about 3n)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;1,000,000&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100,000&lt;/td&gt;
&lt;td&gt;10,000,000,000&lt;/td&gt;
&lt;td&gt;300,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The optimized version needs about &lt;code&gt;n - 1&lt;/code&gt; questions to find a candidate, plus about &lt;code&gt;2(n - 1)&lt;/code&gt; to verify. That is roughly &lt;code&gt;3n&lt;/code&gt;, which is still O(n).&lt;/p&gt;




&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the verification phase.&lt;/strong&gt; The most common bug. See the all zeros matrix above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking &lt;code&gt;M[i][i]&lt;/code&gt;.&lt;/strong&gt; A person knowing themselves is usually &lt;code&gt;0&lt;/code&gt; or ignored. Always skip &lt;code&gt;i == candidate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixing up the direction.&lt;/strong&gt; &lt;code&gt;M[a][b]&lt;/code&gt; means "a knows b", not the other way around. Read it out loud while coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using the wrong elimination rule.&lt;/strong&gt; If &lt;code&gt;a&lt;/code&gt; knows &lt;code&gt;b&lt;/code&gt;, eliminate &lt;code&gt;a&lt;/code&gt; (not &lt;code&gt;b&lt;/code&gt;). I've flipped this more than once at 1 AM.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The interview version
&lt;/h2&gt;

&lt;p&gt;In interviews you often don't get the matrix. You get a function instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is the same, and the number of calls to &lt;code&gt;knows&lt;/code&gt; is what gets measured. The same algorithm drops right in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findCelebrity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;knows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small optimization worth mentioning to your interviewer: you can &lt;strong&gt;cache&lt;/strong&gt; results of &lt;code&gt;knows&lt;/code&gt; so you never ask the same question twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick quiz
&lt;/h2&gt;

&lt;p&gt;Test yourself before looking at the answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1.&lt;/strong&gt; In Phase 1, &lt;code&gt;candidate = 4&lt;/code&gt; and &lt;code&gt;M[4][7] = 0&lt;/code&gt;. What happens?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
Person 4 doesn't know person 7, so &lt;strong&gt;7 cannot be the celebrity&lt;/strong&gt; (a celebrity must be known by everyone). We keep 4 as the candidate and move on.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2.&lt;/strong&gt; Can the algorithm return a wrong answer without Phase 2?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
Yes. Phase 1 always produces a candidate, even when no celebrity exists. Phase 2 is what confirms it.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3.&lt;/strong&gt; What would the time complexity be if we verified &lt;em&gt;every&lt;/em&gt; person instead of only the final candidate?&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Answer
  &lt;br&gt;
That's just the brute force approach again, so &lt;strong&gt;O(n²)&lt;/strong&gt;. The whole point of elimination is that we only fully verify one person.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A celebrity is known by everyone and knows no one.&lt;/li&gt;
&lt;li&gt;There can be &lt;strong&gt;at most one&lt;/strong&gt; celebrity.&lt;/li&gt;
&lt;li&gt;Every question &lt;code&gt;knows(a, b)&lt;/code&gt; rules out exactly one of the two people.&lt;/li&gt;
&lt;li&gt;Eliminate first, &lt;strong&gt;verify second&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Brute force is O(n²). The elimination approach is &lt;strong&gt;O(n) time and O(1) space&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bigger lesson isn't about celebrities. It's this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Can each step of my algorithm throw away part of the problem?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That mindset shows up in binary search, two pointers, monotonic stacks, and many other patterns. Once you start looking for it, you'll see it everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  🥋 Want to practice problems like this?
&lt;/h2&gt;

&lt;p&gt;Understanding the solution is one thing.&lt;/p&gt;

&lt;p&gt;Being able to solve a new problem on your own is another.&lt;/p&gt;

&lt;p&gt;That's why I've been exploring &lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;ScaleDojo&lt;/a&gt;, a hands-on platform for practicing system design, LLD, API design, and algorithmic problem-solving.&lt;/p&gt;

&lt;p&gt;Instead of only reading the solution, you can practice concepts through interactive challenges and get feedback on your approach.&lt;/p&gt;

&lt;p&gt;If you're preparing for technical interviews or simply trying to become better at problem-solving, it's worth checking out:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://scaledojo.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Try ScaleDojo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More practice problems
&lt;/h2&gt;

&lt;p&gt;If you want to keep going with the same pattern, try these next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/find-the-celebrity/" rel="noopener noreferrer"&gt;Find the Celebrity (LeetCode 277)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/find-the-town-judge/" rel="noopener noreferrer"&gt;Find the Town Judge (LeetCode 997)&lt;/a&gt;, a very close cousin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/find-center-of-star-graph/" rel="noopener noreferrer"&gt;Find Center of Star Graph (LeetCode 1791)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your turn 👇
&lt;/h2&gt;

&lt;p&gt;Did you solve this with the stack, two pointers, or something even cleverer? Drop your approach (or your favorite language) in the comments. I'd love to see a Rust or Go version!&lt;/p&gt;

&lt;p&gt;And one more question for you: &lt;strong&gt;what's the first thing you'd check if your app slowed down after hitting 10x traffic?&lt;/strong&gt; I'm curious what everyone's instinct is.&lt;/p&gt;

&lt;p&gt;If this post helped you, a ❤️ or 🦄 helps more beginners find it, and following me means you won't miss the next one in this series. Thanks for reading, and happy coding!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>python</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ritesh Gupta</dc:creator>
      <pubDate>Tue, 15 Sep 2026 14:42:05 +0000</pubDate>
      <link>https://dev.to/riteshgupta_09/-5d81</link>
      <guid>https://dev.to/riteshgupta_09/-5d81</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/riteshgupta_09/what-is-system-design-a-practical-guide-for-developers-who-just-want-to-get-it-4dgb" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feonkc1pha4b9pmtmdx29.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/riteshgupta_09/what-is-system-design-a-practical-guide-for-developers-who-just-want-to-get-it-4dgb" rel="noopener noreferrer" class="c-link"&gt;
            What Is System Design? A Practical Guide for Developers Who Just Want to "Get It" - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            The first time someone said "design a system like Twitter" to me, my brain did this weird glitchy...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>What Is System Design? A Practical Guide for Developers Who Just Want to "Get It"</title>
      <dc:creator>Ritesh Gupta</dc:creator>
      <pubDate>Tue, 15 Sep 2026 14:40:11 +0000</pubDate>
      <link>https://dev.to/riteshgupta_09/what-is-system-design-a-practical-guide-for-developers-who-just-want-to-get-it-4dgb</link>
      <guid>https://dev.to/riteshgupta_09/what-is-system-design-a-practical-guide-for-developers-who-just-want-to-get-it-4dgb</guid>
      <description>&lt;p&gt;The first time someone said "design a system like Twitter" to me, my brain did this weird glitchy thing where it just... stopped. I could build a to-do app. I could write a REST API. I could center a div (okay, that one took longer). But "design a system"? That felt like being asked to build a car when I'd only ever changed a tire.&lt;/p&gt;

&lt;p&gt;If that sounds familiar, you're exactly who this post is for.&lt;/p&gt;

&lt;p&gt;This is my first post on dev.to, so let's make it count no dry textbook definitions, no 40-page whitepaper energy. Just a straight-up, developer-to-developer walkthrough of what system design actually is, why it matters, and how to start thinking like someone who can design systems not just write code that runs.&lt;/p&gt;

&lt;p&gt;Grab your coffee ☕. Let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, Let's Kill the Scary Myth
&lt;/h2&gt;

&lt;p&gt;Here's the biggest misconception: &lt;strong&gt;system design is not about knowing fancy buzzwords.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't need to memorize "CAP theorem," "eventual consistency," and "consistent hashing" like flashcards to be good at this. Those are &lt;em&gt;tools&lt;/em&gt;. System design is really just one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Figuring out how to structure software so it actually works reliably, at scale, and without falling over when real users show up.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. Everything else load balancers, databases, caching, queues exists to solve that one problem.&lt;/p&gt;

&lt;p&gt;Writing code answers the question &lt;strong&gt;"how do I make this work?"&lt;/strong&gt;&lt;br&gt;
System design answers the question &lt;strong&gt;"how do I make this work when 10 people become 10 million people?"&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Should You, a Regular Developer, Care?
&lt;/h2&gt;

&lt;p&gt;Maybe you're not applying to Google. Maybe you just build stuff for your startup, your client, or your side project. So why bother?&lt;/p&gt;

&lt;p&gt;Because system design thinking shows up everywhere, even in small projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app is slow under load → that's a system design problem.&lt;/li&gt;
&lt;li&gt;Your database keeps timing out → system design.&lt;/li&gt;
&lt;li&gt;Your server crashes when a blog post goes viral → yep, system design.&lt;/li&gt;
&lt;li&gt;You want your app to survive a server restart without losing data → still system design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these concepts doesn't just help you pass interviews (though it absolutely does that too). It helps you &lt;strong&gt;build things that don't fall apart the moment they get popular.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Building Blocks: What You're Actually Juggling
&lt;/h2&gt;

&lt;p&gt;Let's break down system design into the core ingredients. Think of these as the "food groups" of a healthy, scalable system.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Scalability: Handling More Without Breaking
&lt;/h3&gt;

&lt;p&gt;Scalability is your system's ability to handle growth. There are two classic ways to scale:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;Analogy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vertical Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add more power (CPU, RAM) to one machine&lt;/td&gt;
&lt;td&gt;Hiring a stronger worker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Horizontal Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add more machines to share the load&lt;/td&gt;
&lt;td&gt;Hiring more workers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vertical scaling is easy but has a ceiling there's only so much RAM you can cram into one box. Horizontal scaling is how the big players (Netflix, Amazon, etc.) handle massive traffic spreading the load across hundreds or thousands of servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Load Balancers: The Traffic Cops
&lt;/h3&gt;

&lt;p&gt;Imagine one cashier trying to serve an entire mall on Black Friday. Chaos, right?&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;load balancer&lt;/strong&gt; sits in front of your servers and distributes incoming requests across them, so no single server gets overwhelmed. It's the reason your favorite app doesn't collapse when everyone opens it at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Caching: Stop Doing the Same Work Twice
&lt;/h3&gt;

&lt;p&gt;If your database gets asked "what's the weather in Lucknow?" ten thousand times a second, that's ten thousand unnecessary trips to the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt; stores frequently accessed data somewhere fast (like Redis or Memcached) so your system can say "oh, I already know that" instead of doing the expensive lookup every single time.&lt;/p&gt;

&lt;p&gt;Rule of thumb: &lt;strong&gt;if data doesn't change often but is read a LOT, cache it.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Databases: SQL vs NoSQL (and Why It's Not a Fight)
&lt;/h3&gt;

&lt;p&gt;This isn't a "which one is better" debate it's "which one fits your problem."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL (Postgres, MySQL)&lt;/strong&gt; great when your data has clear relationships and you need strong consistency (think: banking transactions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NoSQL (MongoDB, Cassandra, DynamoDB)&lt;/strong&gt; great when you need flexibility and massive horizontal scale (think: social media feeds, logs, sensor data).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As systems grow, you'll also hear about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Replication&lt;/strong&gt; copying your database across multiple servers for reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharding&lt;/strong&gt; splitting one giant database into smaller pieces so no single machine is overloaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. The CAP Theorem (Said Simply)
&lt;/h3&gt;

&lt;p&gt;You'll hear this term thrown around a lot, so here's the plain-English version:&lt;/p&gt;

&lt;p&gt;In a distributed system, you can only reliably guarantee &lt;strong&gt;two&lt;/strong&gt; of these three at the same time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt; everyone sees the same data at the same time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability&lt;/strong&gt; the system always responds, even during failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition Tolerance&lt;/strong&gt; the system keeps working even if parts of it can't talk to each other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since network failures &lt;em&gt;will&lt;/em&gt; happen eventually, you're really choosing between &lt;strong&gt;Consistency&lt;/strong&gt; and &lt;strong&gt;Availability&lt;/strong&gt; when things go wrong. That single decision shapes a huge chunk of real-world architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Message Queues: Let Tasks Wait Their Turn
&lt;/h3&gt;

&lt;p&gt;Not everything needs to happen instantly. If a user uploads a video, do you really need to process it &lt;em&gt;right now&lt;/em&gt;, blocking their entire request?&lt;/p&gt;

&lt;p&gt;Nope. You drop the task into a &lt;strong&gt;message queue&lt;/strong&gt; (like Kafka, RabbitMQ, or SQS), and a separate worker processes it in the background. This keeps your app responsive and decouples "slow work" from "user-facing work."&lt;/p&gt;

&lt;h3&gt;
  
  
  7. CDNs: Serving Content Closer to Users
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Content Delivery Network&lt;/strong&gt; caches your static content (images, videos, JS files) on servers around the world, so a user in Mumbai isn't waiting on a server sitting in Virginia. Faster load times, happier users.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's Actually Design Something: A URL Shortener 🔗
&lt;/h2&gt;

&lt;p&gt;Theory is nice, but let's get our hands dirty. A classic beginner-friendly system design problem: &lt;strong&gt;build something like bit.ly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ask:&lt;/strong&gt; User pastes a long URL, gets back a short one. When someone visits the short URL, they get redirected to the original.&lt;/p&gt;

&lt;p&gt;Here's a simplified way to think through it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API Layer&lt;/strong&gt; a simple endpoint like &lt;code&gt;POST /shorten&lt;/code&gt; takes the long URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ID Generation&lt;/strong&gt; generate a short, unique code (e.g., base62 encoding of an auto-incrementing ID, or a hash).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt; store the mapping: &lt;code&gt;short_code → original_url&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect Endpoint&lt;/strong&gt; &lt;code&gt;GET /:short_code&lt;/code&gt; looks up the original URL and issues a redirect (HTTP 301/302).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt; since popular short links get hit a LOT, cache the hot ones in Redis instead of hitting the database every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale it up&lt;/strong&gt; add a load balancer in front of multiple API servers, and shard the database once you outgrow a single instance.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User → Load Balancer → API Servers → Cache (Redis) → Database
                                   ↳ if cache miss, fallback to DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? It's not magic. It's just asking "what happens at each step, and what breaks first as this grows?"&lt;/p&gt;




&lt;h2&gt;
  
  
  Mistakes Almost Every Beginner Makes (I Made All of These)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jumping straight to "microservices"&lt;/strong&gt; for a project with 10 users. You don't need Kubernetes for your todo app. Start simple, scale when you actually need to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the database until it's a fire.&lt;/strong&gt; Data modeling decisions made on day one haunt you on day 300.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Designing for infinite scale nobody asked for.&lt;/strong&gt; Over-engineering is just as bad as under-engineering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting about failure.&lt;/strong&gt; Ask "what happens if this server dies right now?" more often than you think you need to.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Actually Get Good at This
&lt;/h2&gt;

&lt;p&gt;You don't learn system design by reading one article (yes, even this one). You learn it by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Studying real architectures&lt;/strong&gt; Read engineering blogs from companies like Uber, Netflix, and Discord. They openly explain how they solved massive scale problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practicing real system-design problems&lt;/strong&gt; Platforms like &lt;a href="//Scaledojo.dev"&gt;ScaleDojo &lt;/a&gt;can help you move from simply reading system-design concepts to actually applying them through hands-on challenges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building small versions yourself&lt;/strong&gt; Add caching to a side project. Try horizontal scaling with Docker Compose. Break things on purpose and see what happens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asking "what if this fails?" constantly&lt;/strong&gt; This single question separates junior thinking from senior thinking.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;System design isn't some elite skill reserved for senior engineers with 10 years of experience. It's a &lt;strong&gt;mindset&lt;/strong&gt; one where you zoom out from "does this code work" to "does this system survive contact with the real world."&lt;/p&gt;

&lt;p&gt;Start small. Ask good questions. Break your own toy projects on purpose and figure out how to fix them. That's genuinely how this skill is built one curious "wait, what happens if..." at a time.&lt;/p&gt;

&lt;p&gt;If this helped untangle system design even a little, I'd love to hear about the first "big" system &lt;em&gt;you&lt;/em&gt; ever tried to design drop it in the comments. And if you want, I can turn this into a series: caching deep-dive, database scaling, real interview walkthroughs just say the word. 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is my first post on dev.to feedback (gentle or brutal) is very welcome!&lt;/em&gt; 🙌&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>beginners</category>
      <category>systemdesign</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
