{
  "slug": "lis",
  "title": "DP — Longest Increasing Subsequence",
  "category": "Recursion & DP",
  "difficulty": "medium",
  "complexity": {
    "time": "O(n²)",
    "space": "O(n)"
  },
  "idea": "dp[i] is the length of the longest increasing subsequence that ends at index i. To fill it, look back at every earlier element that is smaller and take the best chain you could extend. The answer is the largest entry.",
  "code": [
    "dp[i] = 1 for all i",
    "for i in 1 .. n-1:",
    "    for j in 0 .. i-1:",
    "        if a[j] < a[i]: dp[i] = max(dp[i], dp[j] + 1)",
    "answer = max(dp)"
  ],
  "example": {
    "array": [
      3,
      1,
      8,
      2,
      5,
      6
    ]
  },
  "invariant": "Each step is the real data structure at that step — the picture is a pure function of it.",
  "stepCount": 22,
  "steps": [
    {
      "i": 0,
      "op": "lanes",
      "caption": "Every element is a chain of length 1 on its own.",
      "note": null,
      "codeLine": 1,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            1,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [],
          "regions": []
        }
      ]
    },
    {
      "i": 1,
      "op": "lanes",
      "caption": "How long a chain can end at 1?",
      "note": null,
      "codeLine": 2,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            "compare",
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 1,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            1,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 1,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 2,
      "op": "lanes",
      "caption": "3 ≥ 1 — cannot extend that one.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            "read",
            "compare",
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 1,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            1,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 1,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 3,
      "op": "lanes",
      "caption": "How long a chain can end at 8?",
      "note": null,
      "codeLine": 2,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            "compare",
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            1,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 4,
      "op": "lanes",
      "caption": "3 < 8, so extend that chain: dp[2] = dp[0] + 1 = 2.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            "read",
            null,
            "compare",
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            1,
            1,
            1
          ],
          "focus": [
            "read",
            null,
            "write",
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 5,
      "op": "lanes",
      "caption": "1 < 8 but that chain is only 1 — no improvement.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            "read",
            "compare",
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            1,
            1,
            1
          ],
          "focus": [
            null,
            "read",
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 2,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 6,
      "op": "lanes",
      "caption": "How long a chain can end at 2?",
      "note": null,
      "codeLine": 2,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            "compare",
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 7,
      "op": "lanes",
      "caption": "3 ≥ 2 — cannot extend that one.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            "read",
            null,
            null,
            "compare",
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            1,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 8,
      "op": "lanes",
      "caption": "1 < 2, so extend that chain: dp[3] = dp[1] + 1 = 2.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            "read",
            null,
            "compare",
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            1,
            1
          ],
          "focus": [
            null,
            "read",
            null,
            "write",
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 9,
      "op": "lanes",
      "caption": "8 ≥ 2 — cannot extend that one.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            "read",
            "compare",
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 3,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 10,
      "op": "lanes",
      "caption": "How long a chain can end at 5?",
      "note": null,
      "codeLine": 2,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            null,
            "compare",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            1,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 11,
      "op": "lanes",
      "caption": "3 < 5, so extend that chain: dp[4] = dp[0] + 1 = 2.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            "read",
            null,
            null,
            null,
            "compare",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            2,
            1
          ],
          "focus": [
            "read",
            null,
            null,
            null,
            "write",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 12,
      "op": "lanes",
      "caption": "1 < 5 but that chain is only 1 — no improvement.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            "read",
            null,
            null,
            "compare",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            2,
            1
          ],
          "focus": [
            null,
            "read",
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 13,
      "op": "lanes",
      "caption": "8 ≥ 5 — cannot extend that one.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            "read",
            null,
            "compare",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            2,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 14,
      "op": "lanes",
      "caption": "2 < 5, so extend that chain: dp[4] = dp[3] + 1 = 3.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            "read",
            "compare",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            1
          ],
          "focus": [
            null,
            null,
            null,
            "read",
            "write",
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 4,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 15,
      "op": "lanes",
      "caption": "How long a chain can end at 6?",
      "note": null,
      "codeLine": 2,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            1
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 16,
      "op": "lanes",
      "caption": "3 < 6, so extend that chain: dp[5] = dp[0] + 1 = 2.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            "read",
            null,
            null,
            null,
            null,
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            2
          ],
          "focus": [
            "read",
            null,
            null,
            null,
            null,
            "write"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 17,
      "op": "lanes",
      "caption": "1 < 6 but that chain is only 1 — no improvement.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            "read",
            null,
            null,
            null,
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            2
          ],
          "focus": [
            null,
            "read",
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 18,
      "op": "lanes",
      "caption": "8 ≥ 6 — cannot extend that one.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            "read",
            null,
            null,
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            2
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 19,
      "op": "lanes",
      "caption": "2 < 6, so extend that chain: dp[5] = dp[3] + 1 = 3.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            "read",
            null,
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            3
          ],
          "focus": [
            null,
            null,
            null,
            "read",
            null,
            "write"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 20,
      "op": "lanes",
      "caption": "5 < 6, so extend that chain: dp[5] = dp[4] + 1 = 4.",
      "note": null,
      "codeLine": 4,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            null,
            "read",
            "compare"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            4
          ],
          "focus": [
            null,
            null,
            null,
            null,
            "read",
            "write"
          ],
          "markers": [
            {
              "name": "i",
              "index": 5,
              "tone": "bound"
            }
          ],
          "regions": []
        }
      ]
    },
    {
      "i": 21,
      "op": "lanes",
      "caption": "The longest increasing subsequence has length 4.",
      "note": null,
      "codeLine": 5,
      "stats": null,
      "lanes": [
        {
          "id": "arr",
          "label": "array",
          "array": [
            3,
            1,
            8,
            2,
            5,
            6
          ],
          "focus": [
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "markers": [],
          "regions": []
        },
        {
          "id": "dp",
          "label": "dp[i] = longest chain ending at i",
          "array": [
            1,
            1,
            2,
            2,
            3,
            4
          ],
          "focus": [
            "settled",
            "settled",
            "settled",
            "settled",
            "settled",
            "target"
          ],
          "markers": [],
          "regions": []
        }
      ]
    }
  ]
}