479/670

479. Remove Comments

Medium

You are given a C++ program as source, a list of strings where source[i] is the i-th physical line of the file.

Strip every comment from it:

  • // starts a line comment — it and everything after it on that physical line is dead.
  • /* starts a block comment — it, everything up to the next */ (possibly many lines later), and the closing */ are all dead.

Markers only count when you are not already inside a comment: a // or /* sitting inside an open block comment is plain text, and a /* appearing after a // on the same line is already dead. When markers overlap, the leftmost one that begins first wins. The */ that closes a block must come strictly after the /* that opened it — the middle character of /*/ does not close anything.

After deletion, code that was separated only by a block comment fuses into a single line (the text before /* and the text after */ join), and any line left empty vanishes. Return the surviving lines, in order, as a list of strings.

The input contains no string literals or quote characters, and every block comment that opens is eventually closed.

Example 1:

Input: source = ["int a = 1;// set a", "int b;/* declare", "b */int c;"]

Output: ["int a = 1;", "int b;int c;"]

Explanation: Line 1 loses its line comment. Line 2 keeps "int b;" and opens a block comment that swallows the rest of line 2 and the start of line 3; when it closes, "int c;" glues onto the pending "int b;" to form one fused line.

Example 2:

Input: source = ["void f() {/* comment // still comment", "more */}", "// gone /* not a block", "int z;"]

Output: ["void f() {}", "int z;"]

Explanation: The // inside the open block comment is plain text, so the block runs until the */ on line 2, fusing "void f() {" with "}". Line 3 starts with //, so the /* after it never opens a block and the whole line dies, leaving nothing — the empty line is dropped.

Constraints:

  • 1 ≤ source.length ≤ 100
  • 1 ≤ source[i].length ≤ 80
  • source[i] consists of printable ASCII characters and contains no quote characters.
  • Every block comment that opens is eventually closed, and no closing */ appears without a matching opener.

Hints:

One boolean is the whole state: "am I inside a block comment right now?" It must survive from one line to the next.

Scan each line with an index and look at two characters at a time. Outside a block: "//" kills the rest of the line, "/*" flips the flag and skips 2 characters. Inside a block: only "*/" matters (skip 2 when you see it); every other character is discarded. After opening with "/*", continue past both characters so the '/' of "/*/" can't double as a closer.

Keep a growing buffer of kept characters that you only flush at the end of a line when you are NOT inside a block — that single rule produces the line-fusing behavior for free, and flushing only non-empty buffers drops the empty lines.

▶ Run checks these sample cases. Submit also runs hidden edge cases.

Input: source = ["int a = 1;// set a", "int b;/* declare", "b */int c;"]

Expected output: ["int a = 1;", "int b;int c;"]